dashboard: Improve the compatibility on the Content-Type header of POST request (#1260)
* Better compatibility of the dashboard to legacy and new sentinel-transport-simple-http (on Content-Type header), related to #1207
This commit is contained in:
parent
b136848873
commit
c5071550fa
|
|
@ -69,6 +69,7 @@ import org.apache.http.client.entity.UrlEncodedFormEntity;
|
|||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.apache.http.concurrent.FutureCallback;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.impl.client.DefaultRedirectStrategy;
|
||||
|
|
@ -93,6 +94,8 @@ public class SentinelApiClient {
|
|||
private static Logger logger = LoggerFactory.getLogger(SentinelApiClient.class);
|
||||
|
||||
private static final Charset DEFAULT_CHARSET = Charset.forName(SentinelConfig.charset());
|
||||
private static final String HTTP_HEADER_CONTENT_TYPE = "Content-Type";
|
||||
private static final String HTTP_HEADER_CONTENT_TYPE_URLENCODED = ContentType.create(URLEncodedUtils.CONTENT_TYPE).toString();
|
||||
|
||||
private static final String RESOURCE_URL_PATH = "jsonTree";
|
||||
private static final String CLUSTER_NODE_PATH = "clusterNode";
|
||||
|
|
@ -106,7 +109,6 @@ public class SentinelApiClient {
|
|||
private static final String FETCH_CLUSTER_CLIENT_CONFIG_PATH = "cluster/client/fetchConfig";
|
||||
private static final String MODIFY_CLUSTER_CLIENT_CONFIG_PATH = "cluster/client/modifyConfig";
|
||||
|
||||
private static final String FETCH_CLUSTER_SERVER_ALL_CONFIG_PATH = "cluster/server/fetchConfig";
|
||||
private static final String FETCH_CLUSTER_SERVER_BASIC_INFO_PATH = "cluster/server/info";
|
||||
|
||||
private static final String MODIFY_CLUSTER_SERVER_TRANSPORT_CONFIG_PATH = "cluster/server/modifyTransportConfig";
|
||||
|
|
@ -127,6 +129,7 @@ public class SentinelApiClient {
|
|||
private CloseableHttpAsyncClient httpClient;
|
||||
|
||||
private static final SentinelVersion version160 = new SentinelVersion(1, 6, 0);
|
||||
private static final SentinelVersion version171 = new SentinelVersion(1, 7, 1);
|
||||
|
||||
@Autowired
|
||||
private AppManagement appManagement;
|
||||
|
|
@ -151,6 +154,30 @@ public class SentinelApiClient {
|
|||
return statusCode == 400 && StringUtil.isNotEmpty(body) && body.contains(CommandConstants.MSG_UNKNOWN_COMMAND_PREFIX);
|
||||
}
|
||||
|
||||
protected boolean isSupportPost(String app, String ip, int port) {
|
||||
return StringUtil.isNotEmpty(app) && Optional.ofNullable(appManagement.getDetailApp(app))
|
||||
.flatMap(e -> e.getMachine(ip, port))
|
||||
.flatMap(m -> VersionUtils.parseVersion(m.getVersion())
|
||||
.map(v -> v.greaterOrEqual(version160)))
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check wheter target instance (identified by tuple of app-ip:port)
|
||||
* supports the form of "xxxxx; xx=xx" in "Content-Type" header.
|
||||
*
|
||||
* @param app target app name
|
||||
* @param ip target node's address
|
||||
* @param port target node's port
|
||||
*/
|
||||
protected boolean isSupportEnhancedContentType(String app, String ip, int port) {
|
||||
return StringUtil.isNotEmpty(app) && Optional.ofNullable(appManagement.getDetailApp(app))
|
||||
.flatMap(e -> e.getMachine(ip, port))
|
||||
.flatMap(m -> VersionUtils.parseVersion(m.getVersion())
|
||||
.map(v -> v.greaterOrEqual(version171)))
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
private StringBuilder queryString(Map<String, String> params) {
|
||||
StringBuilder queryStringBuilder = new StringBuilder();
|
||||
for (Entry<String, String> entry : params.entrySet()) {
|
||||
|
|
@ -169,7 +196,15 @@ public class SentinelApiClient {
|
|||
return queryStringBuilder;
|
||||
}
|
||||
|
||||
private HttpUriRequest postRequest(String url, Map<String, String> params) {
|
||||
/**
|
||||
* Build an `HttpUriRequest` in POST way.
|
||||
*
|
||||
* @param url
|
||||
* @param params
|
||||
* @param supportEnhancedContentType see {@link #isSupportEnhancedContentType(String, String, int)}
|
||||
* @return
|
||||
*/
|
||||
protected static HttpUriRequest postRequest(String url, Map<String, String> params, boolean supportEnhancedContentType) {
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
if (params != null && params.size() > 0) {
|
||||
List<NameValuePair> list = new ArrayList<>(params.size());
|
||||
|
|
@ -177,6 +212,9 @@ public class SentinelApiClient {
|
|||
list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
httpPost.setEntity(new UrlEncodedFormEntity(list, Consts.UTF_8));
|
||||
if (!supportEnhancedContentType) {
|
||||
httpPost.setHeader(HTTP_HEADER_CONTENT_TYPE, HTTP_HEADER_CONTENT_TYPE_URLENCODED);
|
||||
}
|
||||
}
|
||||
return httpPost;
|
||||
}
|
||||
|
|
@ -193,7 +231,7 @@ public class SentinelApiClient {
|
|||
private String getBody(HttpResponse response) throws Exception {
|
||||
Charset charset = null;
|
||||
try {
|
||||
String contentTypeStr = response.getFirstHeader("Content-type").getValue();
|
||||
String contentTypeStr = response.getFirstHeader(HTTP_HEADER_CONTENT_TYPE).getValue();
|
||||
if (StringUtil.isNotEmpty(contentTypeStr)) {
|
||||
ContentType contentType = ContentType.parse(contentTypeStr);
|
||||
charset = contentType.getCharset();
|
||||
|
|
@ -250,12 +288,7 @@ public class SentinelApiClient {
|
|||
if (params == null) {
|
||||
params = Collections.emptyMap();
|
||||
}
|
||||
boolean supportPost = StringUtil.isNotEmpty(app) && Optional.ofNullable(appManagement.getDetailApp(app))
|
||||
.flatMap(e -> e.getMachine(ip, port))
|
||||
.flatMap(m -> VersionUtils.parseVersion(m.getVersion())
|
||||
.map(v -> v.greaterOrEqual(version160)))
|
||||
.orElse(false);
|
||||
if (!useHttpPost || !supportPost) {
|
||||
if (!useHttpPost || !isSupportPost(app, ip, port)) {
|
||||
// Using GET in older versions, append parameters after url
|
||||
if (!params.isEmpty()) {
|
||||
if (urlBuilder.indexOf("?") == -1) {
|
||||
|
|
@ -268,7 +301,8 @@ public class SentinelApiClient {
|
|||
return executeCommand(new HttpGet(urlBuilder.toString()));
|
||||
} else {
|
||||
// Using POST
|
||||
return executeCommand(postRequest(urlBuilder.toString(), params));
|
||||
return executeCommand(
|
||||
postRequest(urlBuilder.toString(), params, isSupportEnhancedContentType(app, ip, port)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.dashboard.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.protocol.RequestContent;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SentinelApiClientTest {
|
||||
@Test
|
||||
public void postRequest() throws HttpException, IOException {
|
||||
// Processor is required because it will determine the final request body including
|
||||
// headers before outgoing.
|
||||
RequestContent processor = new RequestContent();
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
params.put("a", "1");
|
||||
params.put("b", "2+");
|
||||
params.put("c", "3 ");
|
||||
|
||||
HttpUriRequest request;
|
||||
|
||||
request = SentinelApiClient.postRequest("/test", params, false);
|
||||
assertNotNull(request);
|
||||
processor.process(request, null);
|
||||
assertNotNull(request.getFirstHeader("Content-Type"));
|
||||
assertEquals("application/x-www-form-urlencoded", request.getFirstHeader("Content-Type").getValue());
|
||||
|
||||
request = SentinelApiClient.postRequest("/test", params, true);
|
||||
assertNotNull(request);
|
||||
processor.process(request, null);
|
||||
assertNotNull(request.getFirstHeader("Content-Type"));
|
||||
assertEquals("application/x-www-form-urlencoded; charset=UTF-8", request.getFirstHeader("Content-Type").getValue());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue