parent
3fcfbbb820
commit
26481c13de
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* 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.tencent.cloud.polaris.gateway.core.zuul.discovery;
|
||||||
|
|
||||||
|
import com.tencent.cloud.metadata.context.MetadataContextHolder;
|
||||||
|
import com.tencent.polaris.api.core.ConsumerAPI;
|
||||||
|
import com.tencent.polaris.api.pojo.Instance;
|
||||||
|
import com.tencent.polaris.api.rpc.GetAllInstancesRequest;
|
||||||
|
import com.tencent.polaris.api.rpc.InstancesResponse;
|
||||||
|
import com.tencent.polaris.factory.api.DiscoveryAPIFactory;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: hongyihui
|
||||||
|
*/
|
||||||
|
public class PolarisProviderDiscovery {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(PolarisProviderDiscovery.class);
|
||||||
|
private static final Map<String, List<Instance>> polarisProviderMap = new ConcurrentHashMap<>();
|
||||||
|
private static final Timer getAllServiceProviderTimer = new Timer("PolarisProviderDiscovery.getAllServiceProviderTimer", true);
|
||||||
|
|
||||||
|
private ZuulProperties zuulProperties;
|
||||||
|
|
||||||
|
public PolarisProviderDiscovery(ZuulProperties zuulProperties) {
|
||||||
|
this.zuulProperties = zuulProperties;
|
||||||
|
|
||||||
|
getAllServiceProvider();
|
||||||
|
|
||||||
|
getAllServiceProviderTimer.schedule(new TimerTask() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
getAllServiceProvider();
|
||||||
|
}
|
||||||
|
}, 10000, 30000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getAllServiceProvider() {
|
||||||
|
Map<String, ZuulProperties.ZuulRoute> zuulRouteMap = zuulProperties.getRoutes();
|
||||||
|
if (zuulRouteMap != null && zuulRouteMap.size() > 0) {
|
||||||
|
ConsumerAPI consumerAPI = DiscoveryAPIFactory.createConsumerAPI();
|
||||||
|
for (Map.Entry<String, ZuulProperties.ZuulRoute> entry : zuulRouteMap.entrySet()) {
|
||||||
|
ZuulProperties.ZuulRoute zuulRoute = entry.getValue();
|
||||||
|
String serviceId = zuulRoute.getServiceId();
|
||||||
|
|
||||||
|
GetAllInstancesRequest getAllInstancesRequest = new GetAllInstancesRequest();
|
||||||
|
getAllInstancesRequest.setNamespace(MetadataContextHolder.LOCAL_NAMESPACE);
|
||||||
|
getAllInstancesRequest.setService(serviceId);
|
||||||
|
InstancesResponse instancesResponse = consumerAPI.getAllInstance(getAllInstancesRequest);
|
||||||
|
for (Instance instance : instancesResponse.getInstances()) {
|
||||||
|
LOG.info("instance is " + instance.getHost() + ":" + instance.getPort());
|
||||||
|
}
|
||||||
|
polarisProviderMap.put(MetadataContextHolder.LOCAL_NAMESPACE + "." + serviceId, Arrays.asList(instancesResponse.getInstances()));
|
||||||
|
}
|
||||||
|
consumerAPI.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instance selectProvider(String namespace, String serviceId) {
|
||||||
|
if (polarisProviderMap.size() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<Instance> instances = polarisProviderMap.get(namespace + "." + serviceId);
|
||||||
|
if (instances == null || instances.size() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// random select
|
||||||
|
Random random = new Random();
|
||||||
|
int selectIndex = random.nextInt(instances.size());
|
||||||
|
return instances.get(selectIndex);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,442 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* 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.tencent.cloud.polaris.gateway.core.zuul.filter;
|
||||||
|
|
||||||
|
import com.netflix.client.ClientException;
|
||||||
|
import com.netflix.zuul.ZuulFilter;
|
||||||
|
import com.netflix.zuul.context.RequestContext;
|
||||||
|
import com.netflix.zuul.exception.ZuulException;
|
||||||
|
import com.tencent.cloud.metadata.constant.MetadataConstant;
|
||||||
|
import com.tencent.cloud.metadata.context.MetadataContextHolder;
|
||||||
|
import com.tencent.cloud.polaris.gateway.core.zuul.discovery.PolarisProviderDiscovery;
|
||||||
|
import com.tencent.cloud.polaris.ratelimit.utils.Consts;
|
||||||
|
import com.tencent.polaris.api.pojo.Instance;
|
||||||
|
import org.apache.http.Header;
|
||||||
|
import org.apache.http.HttpHost;
|
||||||
|
import org.apache.http.HttpRequest;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.config.CookieSpecs;
|
||||||
|
import org.apache.http.client.config.RequestConfig;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpPatch;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.client.methods.HttpPut;
|
||||||
|
import org.apache.http.conn.HttpClientConnectionManager;
|
||||||
|
import org.apache.http.entity.ContentType;
|
||||||
|
import org.apache.http.entity.InputStreamEntity;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.message.BasicHeader;
|
||||||
|
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
|
||||||
|
import org.apache.http.message.BasicHttpRequest;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.cloud.commons.httpclient.ApacheHttpClientConnectionManagerFactory;
|
||||||
|
import org.springframework.cloud.commons.httpclient.ApacheHttpClientFactory;
|
||||||
|
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
|
||||||
|
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
|
||||||
|
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
|
||||||
|
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.Host;
|
||||||
|
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
|
||||||
|
import org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException;
|
||||||
|
import org.springframework.context.ApplicationListener;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: hongyihui
|
||||||
|
*/
|
||||||
|
public class PolarisRpcZuulFilter extends ZuulFilter implements ApplicationListener<EnvironmentChangeEvent> {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(PolarisRpcZuulFilter.class);
|
||||||
|
|
||||||
|
private final Timer connectionManagerTimer = new Timer("PolarisRpcZuulFilter.connectionManagerTimer", true);
|
||||||
|
|
||||||
|
private boolean sslHostnameValidationEnabled;
|
||||||
|
|
||||||
|
private boolean forceOriginalQueryStringEncoding;
|
||||||
|
|
||||||
|
private ProxyRequestHelper helper;
|
||||||
|
|
||||||
|
private ZuulProperties properties;
|
||||||
|
|
||||||
|
private Host hostProperties;
|
||||||
|
|
||||||
|
private ApacheHttpClientConnectionManagerFactory connectionManagerFactory;
|
||||||
|
|
||||||
|
private ApacheHttpClientFactory httpClientFactory;
|
||||||
|
|
||||||
|
private HttpClientConnectionManager connectionManager;
|
||||||
|
|
||||||
|
private CloseableHttpClient httpClient;
|
||||||
|
|
||||||
|
private boolean useServlet31 = true;
|
||||||
|
|
||||||
|
private PolarisProviderDiscovery polarisProviderDiscovery;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("Deprecation")
|
||||||
|
public void onApplicationEvent(EnvironmentChangeEvent event) {
|
||||||
|
onPropertyChange(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public void onPropertyChange(EnvironmentChangeEvent event) {
|
||||||
|
boolean createNewClient = false;
|
||||||
|
|
||||||
|
for (String key : event.getKeys()) {
|
||||||
|
if (key.startsWith("zuul.host.")) {
|
||||||
|
createNewClient = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createNewClient) {
|
||||||
|
try {
|
||||||
|
this.httpClient.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOG.error("error closing client", ex);
|
||||||
|
}
|
||||||
|
// Re-create connection manager (may be shut down on HTTP client close)
|
||||||
|
try {
|
||||||
|
this.connectionManager.shutdown();
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
LOG.error("error shutting down connection manager", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.connectionManager = newConnectionManager();
|
||||||
|
this.httpClient = newClient();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PolarisRpcZuulFilter(ProxyRequestHelper helper, ZuulProperties properties,
|
||||||
|
ApacheHttpClientConnectionManagerFactory connectionManagerFactory,
|
||||||
|
ApacheHttpClientFactory httpClientFactory, PolarisProviderDiscovery polarisProviderDiscovery) {
|
||||||
|
this.helper = helper;
|
||||||
|
|
||||||
|
this.properties = properties;
|
||||||
|
this.hostProperties = properties.getHost();
|
||||||
|
this.sslHostnameValidationEnabled = properties.isSslHostnameValidationEnabled();
|
||||||
|
this.forceOriginalQueryStringEncoding = properties.isForceOriginalQueryStringEncoding();
|
||||||
|
|
||||||
|
this.connectionManagerFactory = connectionManagerFactory;
|
||||||
|
this.httpClientFactory = httpClientFactory;
|
||||||
|
|
||||||
|
this.polarisProviderDiscovery = polarisProviderDiscovery;
|
||||||
|
checkServletVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void checkServletVersion() {
|
||||||
|
// To support Servlet API 3.1 we need to check if getContentLengthLong exists
|
||||||
|
// Spring 5 minimum support is 3.0, so this stays
|
||||||
|
try {
|
||||||
|
HttpServletRequest.class.getMethod("getContentLengthLong");
|
||||||
|
useServlet31 = true;
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
useServlet31 = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
private void initialize() {
|
||||||
|
this.connectionManager = newConnectionManager();
|
||||||
|
this.httpClient = newClient();
|
||||||
|
|
||||||
|
this.connectionManagerTimer.schedule(new TimerTask() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (PolarisRpcZuulFilter.this.connectionManager == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PolarisRpcZuulFilter.this.connectionManager.closeExpiredConnections();
|
||||||
|
}
|
||||||
|
}, 30000, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HttpClientConnectionManager newConnectionManager() {
|
||||||
|
return connectionManagerFactory.newConnectionManager(
|
||||||
|
!this.sslHostnameValidationEnabled,
|
||||||
|
this.hostProperties.getMaxTotalConnections(),
|
||||||
|
this.hostProperties.getMaxPerRouteConnections(),
|
||||||
|
this.hostProperties.getTimeToLive(), this.hostProperties.getTimeUnit(),
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CloseableHttpClient newClient() {
|
||||||
|
final RequestConfig requestConfig = RequestConfig.custom()
|
||||||
|
.setConnectionRequestTimeout(this.hostProperties.getConnectionRequestTimeoutMillis())
|
||||||
|
.setSocketTimeout(this.hostProperties.getSocketTimeoutMillis())
|
||||||
|
.setConnectTimeout(this.hostProperties.getConnectTimeoutMillis())
|
||||||
|
.setCookieSpec(CookieSpecs.IGNORE_COOKIES).build();
|
||||||
|
return httpClientFactory.createBuilder().setDefaultRequestConfig(requestConfig)
|
||||||
|
.setConnectionManager(this.connectionManager).disableRedirectHandling()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void stop() {
|
||||||
|
this.connectionManagerTimer.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String filterType() {
|
||||||
|
return FilterConstants.ROUTE_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int filterOrder() {
|
||||||
|
return FilterConstants.RIBBON_ROUTING_FILTER_ORDER - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldFilter() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object run() {
|
||||||
|
RequestContext context = RequestContext.getCurrentContext();
|
||||||
|
HttpServletRequest request = context.getRequest();
|
||||||
|
MultiValueMap<String, String> headers = this.helper.buildZuulRequestHeaders(request);
|
||||||
|
MultiValueMap<String, String> params = this.helper.buildZuulRequestQueryParams(request);
|
||||||
|
String verb = getVerb(request);
|
||||||
|
InputStream requestEntity = getRequestBody(request);
|
||||||
|
if (getContentLength(request) < 0) {
|
||||||
|
context.setChunkedRequestBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
String uri = this.helper.buildZuulRequestURI(request);
|
||||||
|
this.helper.addIgnoredHeaders();
|
||||||
|
|
||||||
|
try {
|
||||||
|
String peerNamespace = MetadataContextHolder.get().getSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_NAMESPACE);
|
||||||
|
String serviceId = (String) context.get(FilterConstants.SERVICE_ID_KEY);
|
||||||
|
String proxy = (String) context.get(FilterConstants.PROXY_KEY);
|
||||||
|
// TODO retry
|
||||||
|
Boolean retryable = (Boolean) context.get(FilterConstants.RETRYABLE_KEY);
|
||||||
|
|
||||||
|
Instance instance = polarisProviderDiscovery.selectProvider(peerNamespace, serviceId);
|
||||||
|
if (instance == null) {
|
||||||
|
// skip later execution
|
||||||
|
context.setSendZuulResponse(false);
|
||||||
|
|
||||||
|
context.setResponseStatusCode(HttpStatus.BAD_GATEWAY.value());
|
||||||
|
context.getResponse().getWriter().write(Consts.QUOTA_LIMITED_INFO + "no providers");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
uri = handleUri(instance, proxy, uri);
|
||||||
|
CloseableHttpResponse response = forward(this.httpClient, verb, uri, request, headers, params, requestEntity);
|
||||||
|
setResponse(response);
|
||||||
|
|
||||||
|
// skip later execution
|
||||||
|
context.setSendZuulResponse(false);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new ZuulRuntimeException(handleException(ex));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getVerb(HttpServletRequest request) {
|
||||||
|
String sMethod = request.getMethod();
|
||||||
|
return sMethod.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected InputStream getRequestBody(HttpServletRequest request) {
|
||||||
|
InputStream requestEntity = null;
|
||||||
|
try {
|
||||||
|
requestEntity = (InputStream) RequestContext.getCurrentContext().get(FilterConstants.REQUEST_ENTITY_KEY);
|
||||||
|
if (requestEntity == null) {
|
||||||
|
requestEntity = request.getInputStream();
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOG.error("error during getRequestBody", ex);
|
||||||
|
}
|
||||||
|
return requestEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the header value as a long in order to more correctly proxy very large requests
|
||||||
|
protected long getContentLength(HttpServletRequest request) {
|
||||||
|
if (useServlet31) {
|
||||||
|
return request.getContentLengthLong();
|
||||||
|
}
|
||||||
|
String contentLengthHeader = request.getHeader(HttpHeaders.CONTENT_LENGTH);
|
||||||
|
if (contentLengthHeader != null) {
|
||||||
|
try {
|
||||||
|
return Long.parseLong(contentLengthHeader);
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return request.getContentLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String handleUri(Instance instance, String prefix, String uri) {
|
||||||
|
if (!uri.startsWith("/")) {
|
||||||
|
uri = "/" + uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle stripPrefix
|
||||||
|
if (uri.startsWith("/" + prefix) && this.properties.isStripPrefix()) {
|
||||||
|
uri = uri.substring(1 + prefix.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
return "http://" + instance.getHost() + ":" + instance.getPort() + uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CloseableHttpResponse forward(CloseableHttpClient httpclient, String verb, String uri,
|
||||||
|
HttpServletRequest request, MultiValueMap<String, String> headers,
|
||||||
|
MultiValueMap<String, String> params, InputStream requestEntity) throws Exception {
|
||||||
|
URL host = new URL(uri);
|
||||||
|
HttpHost httpHost = getHttpHost(host);
|
||||||
|
long contentLength = getContentLength(request);
|
||||||
|
|
||||||
|
ContentType contentType = null;
|
||||||
|
|
||||||
|
if (request.getContentType() != null) {
|
||||||
|
contentType = ContentType.parse(request.getContentType());
|
||||||
|
}
|
||||||
|
|
||||||
|
InputStreamEntity entity = new InputStreamEntity(requestEntity, contentLength, contentType);
|
||||||
|
|
||||||
|
HttpRequest httpRequest = buildHttpRequest(verb, uri, entity, headers, params, request);
|
||||||
|
LOG.debug(httpHost.getHostName() + " " + httpHost.getPort() + " " + httpHost.getSchemeName());
|
||||||
|
return forwardRequest(httpclient, httpHost, httpRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HttpHost getHttpHost(URL host) {
|
||||||
|
return new HttpHost(host.getHost(), host.getPort(), host.getProtocol());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HttpRequest buildHttpRequest(String verb, String uri, InputStreamEntity entity,
|
||||||
|
MultiValueMap<String, String> headers, MultiValueMap<String, String> params,
|
||||||
|
HttpServletRequest request) {
|
||||||
|
HttpRequest httpRequest;
|
||||||
|
String uriWithQueryString = uri + (this.forceOriginalQueryStringEncoding ? getEncodedQueryString(request)
|
||||||
|
: this.helper.getQueryString(params));
|
||||||
|
|
||||||
|
switch (verb.toUpperCase()) {
|
||||||
|
case "POST":
|
||||||
|
HttpPost httpPost = new HttpPost(uriWithQueryString);
|
||||||
|
httpRequest = httpPost;
|
||||||
|
httpPost.setEntity(entity);
|
||||||
|
break;
|
||||||
|
case "PUT":
|
||||||
|
HttpPut httpPut = new HttpPut(uriWithQueryString);
|
||||||
|
httpRequest = httpPut;
|
||||||
|
httpPut.setEntity(entity);
|
||||||
|
break;
|
||||||
|
case "PATCH":
|
||||||
|
HttpPatch httpPatch = new HttpPatch(uriWithQueryString);
|
||||||
|
httpRequest = httpPatch;
|
||||||
|
httpPatch.setEntity(entity);
|
||||||
|
break;
|
||||||
|
case "DELETE":
|
||||||
|
BasicHttpEntityEnclosingRequest entityRequest = new BasicHttpEntityEnclosingRequest(verb, uriWithQueryString);
|
||||||
|
httpRequest = entityRequest;
|
||||||
|
entityRequest.setEntity(entity);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
httpRequest = new BasicHttpRequest(verb, uriWithQueryString);
|
||||||
|
LOG.debug(uriWithQueryString);
|
||||||
|
}
|
||||||
|
|
||||||
|
httpRequest.setHeaders(convertHeaders(headers));
|
||||||
|
|
||||||
|
return httpRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getEncodedQueryString(HttpServletRequest request) {
|
||||||
|
String query = request.getQueryString();
|
||||||
|
return (query != null) ? "?" + query : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Header[] convertHeaders(MultiValueMap<String, String> headers) {
|
||||||
|
List<Header> list = new ArrayList<>();
|
||||||
|
for (String name : headers.keySet()) {
|
||||||
|
for (String value : headers.get(name)) {
|
||||||
|
list.add(new BasicHeader(name, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list.toArray(new BasicHeader[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MultiValueMap<String, String> revertHeaders(Header[] headers) {
|
||||||
|
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
|
||||||
|
for (Header header : headers) {
|
||||||
|
String name = header.getName();
|
||||||
|
if (!map.containsKey(name)) {
|
||||||
|
map.put(name, new ArrayList<>());
|
||||||
|
}
|
||||||
|
map.get(name).add(header.getValue());
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CloseableHttpResponse forwardRequest(CloseableHttpClient httpclient, HttpHost httpHost,
|
||||||
|
HttpRequest httpRequest) throws IOException {
|
||||||
|
return httpclient.execute(httpHost, httpRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setResponse(HttpResponse response) throws IOException {
|
||||||
|
RequestContext.getCurrentContext().set("zuulResponse", response);
|
||||||
|
this.helper.setResponse(response.getStatusLine().getStatusCode(),
|
||||||
|
response.getEntity() == null ? null : response.getEntity().getContent(),
|
||||||
|
revertHeaders(response.getAllHeaders()));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ZuulException handleException(Exception ex) {
|
||||||
|
int statusCode = HttpStatus.INTERNAL_SERVER_ERROR.value();
|
||||||
|
Throwable cause = ex;
|
||||||
|
String message = ex.getMessage();
|
||||||
|
|
||||||
|
ClientException clientException = findClientException(ex);
|
||||||
|
|
||||||
|
if (clientException != null) {
|
||||||
|
if (clientException
|
||||||
|
.getErrorType() == ClientException.ErrorType.SERVER_THROTTLED) {
|
||||||
|
statusCode = HttpStatus.SERVICE_UNAVAILABLE.value();
|
||||||
|
}
|
||||||
|
cause = clientException;
|
||||||
|
message = clientException.getErrorType().toString();
|
||||||
|
}
|
||||||
|
return new ZuulException(cause, "Forwarding error", statusCode, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ClientException findClientException(Throwable t) {
|
||||||
|
if (t == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (t instanceof ClientException) {
|
||||||
|
return (ClientException) t;
|
||||||
|
}
|
||||||
|
return findClientException(t.getCause());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue