Merge pull request #625 from liebowitz/master
* pull625: Refactor SimpleHostRoutingFilter
This commit is contained in:
@@ -19,15 +19,9 @@ package org.springframework.cloud.netflix.zuul.filters.route;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.Socket;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
@@ -35,8 +29,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
@@ -44,30 +37,31 @@ import javax.net.ssl.X509TrustManager;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.ProtocolException;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.RedirectStrategy;
|
||||
import org.apache.http.client.config.CookieSpecs;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
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.client.params.ClientPNames;
|
||||
import org.apache.http.conn.ClientConnectionManager;
|
||||
import org.apache.http.conn.scheme.PlainSocketFactory;
|
||||
import org.apache.http.conn.scheme.Scheme;
|
||||
import org.apache.http.conn.scheme.SchemeRegistry;
|
||||
import org.apache.http.conn.ssl.SSLSocketFactory;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.config.Registry;
|
||||
import org.apache.http.config.RegistryBuilder;
|
||||
import org.apache.http.conn.socket.ConnectionSocketFactory;
|
||||
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.entity.InputStreamEntity;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
|
||||
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicHttpRequest;
|
||||
import org.apache.http.params.CoreConnectionPNames;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
@@ -80,19 +74,11 @@ import com.netflix.zuul.ZuulFilter;
|
||||
import com.netflix.zuul.constants.ZuulConstants;
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
@CommonsLog
|
||||
@SuppressWarnings("deprecation")
|
||||
public class SimpleHostRoutingFilter extends ZuulFilter {
|
||||
|
||||
public static final String CONTENT_ENCODING = "Content-Encoding";
|
||||
|
||||
private static final Runnable CLIENTLOADER = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
loadClient();
|
||||
}
|
||||
};
|
||||
|
||||
private static final DynamicIntProperty SOCKET_TIMEOUT = DynamicPropertyFactory
|
||||
.getInstance().getIntProperty(ZuulConstants.ZUUL_HOST_SOCKET_TIMEOUT_MILLIS,
|
||||
10000);
|
||||
@@ -101,34 +87,24 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
|
||||
.getInstance().getIntProperty(ZuulConstants.ZUUL_HOST_CONNECT_TIMEOUT_MILLIS,
|
||||
2000);
|
||||
|
||||
private static final AtomicReference<HttpClient> CLIENT = new AtomicReference<HttpClient>(
|
||||
newClient());
|
||||
|
||||
private static final Timer CONNECTION_MANAGER_TIMER = new Timer(
|
||||
"SimpleHostRoutingFilter.CONNECTION_MANAGER_TIMER", true);
|
||||
|
||||
// cleans expired connections at an interval
|
||||
static {
|
||||
SOCKET_TIMEOUT.addCallback(CLIENTLOADER);
|
||||
CONNECTION_TIMEOUT.addCallback(CLIENTLOADER);
|
||||
CONNECTION_MANAGER_TIMER.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
final HttpClient hc = CLIENT.get();
|
||||
if (hc == null) {
|
||||
return;
|
||||
}
|
||||
hc.getConnectionManager().closeExpiredConnections();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
log.error("error closing expired connections", ex);
|
||||
}
|
||||
}
|
||||
}, 30000, 5000);
|
||||
}
|
||||
private final Timer connectionManagerTimer = new Timer(
|
||||
"SimpleHostRoutingFilter.connectionManagerTimer", true);
|
||||
|
||||
private ProxyRequestHelper helper;
|
||||
private PoolingHttpClientConnectionManager connectionManager;
|
||||
private CloseableHttpClient httpClient;
|
||||
|
||||
private final Runnable clientloader = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
httpClient.close();
|
||||
} catch (IOException ex) {
|
||||
log.error("error closing client", ex);
|
||||
}
|
||||
httpClient = newClient();
|
||||
}
|
||||
};
|
||||
|
||||
public SimpleHostRoutingFilter() {
|
||||
this(new ProxyRequestHelper());
|
||||
@@ -138,9 +114,25 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
|
||||
this.helper = helper;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
private void initialize() {
|
||||
this.httpClient = newClient();
|
||||
SOCKET_TIMEOUT.addCallback(clientloader);
|
||||
CONNECTION_TIMEOUT.addCallback(clientloader);
|
||||
connectionManagerTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (connectionManager == null) {
|
||||
return;
|
||||
}
|
||||
connectionManager.closeExpiredConnections();
|
||||
}
|
||||
}, 30000, 5000);
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void stop() {
|
||||
CONNECTION_MANAGER_TIMER.cancel();
|
||||
connectionManagerTimer.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -169,12 +161,11 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
|
||||
.buildZuulRequestQueryParams(request);
|
||||
String verb = getVerb(request);
|
||||
InputStream requestEntity = getRequestBody(request);
|
||||
HttpClient httpclient = CLIENT.get();
|
||||
|
||||
String uri = this.helper.buildZuulRequestURI(request);
|
||||
|
||||
try {
|
||||
HttpResponse response = forward(httpclient, verb, uri, request, headers,
|
||||
HttpResponse response = forward(httpClient, verb, uri, request, headers,
|
||||
params, requestEntity);
|
||||
setResponse(response);
|
||||
}
|
||||
@@ -185,9 +176,66 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected PoolingHttpClientConnectionManager newConnectionManager() {
|
||||
try {
|
||||
final SSLContext sslContext = SSLContext.getInstance("SSL");
|
||||
sslContext.init(null, new TrustManager[]{new X509TrustManager() {
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
}}, new SecureRandom());
|
||||
|
||||
final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
|
||||
.register("http", PlainConnectionSocketFactory.INSTANCE)
|
||||
.register("https", new SSLConnectionSocketFactory(sslContext))
|
||||
.build();
|
||||
|
||||
connectionManager = new PoolingHttpClientConnectionManager(registry);
|
||||
connectionManager.setMaxTotal(Integer.parseInt(System.getProperty("zuul.max.host.connections", "200")));
|
||||
connectionManager.setDefaultMaxPerRoute(Integer.parseInt(System.getProperty("zuul.max.host.connections", "20")));
|
||||
return connectionManager;
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected CloseableHttpClient newClient() {
|
||||
final RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setSocketTimeout(SOCKET_TIMEOUT.get())
|
||||
.setConnectTimeout(CONNECTION_TIMEOUT.get())
|
||||
.setCookieSpec(CookieSpecs.IGNORE_COOKIES)
|
||||
.build();
|
||||
|
||||
return HttpClients.custom()
|
||||
.setConnectionManager(newConnectionManager())
|
||||
.setDefaultRequestConfig(requestConfig)
|
||||
.setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))
|
||||
.setRedirectStrategy(new RedirectStrategy() {
|
||||
@Override
|
||||
public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
private HttpResponse forward(HttpClient httpclient, String verb, String uri,
|
||||
HttpServletRequest request, MultiValueMap<String, String> headers,
|
||||
MultiValueMap<String, String> params, InputStream requestEntity)
|
||||
HttpServletRequest request, MultiValueMap<String, String> headers,
|
||||
MultiValueMap<String, String> params, InputStream requestEntity)
|
||||
throws Exception {
|
||||
Map<String, Object> info = this.helper.debug(verb, uri, headers, params,
|
||||
requestEntity);
|
||||
@@ -306,117 +354,12 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
|
||||
revertHeaders(response.getAllHeaders()));
|
||||
}
|
||||
|
||||
private static ClientConnectionManager newConnectionManager() throws Exception {
|
||||
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
trustStore.load(null, null);
|
||||
SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
|
||||
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
|
||||
SchemeRegistry registry = new SchemeRegistry();
|
||||
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
|
||||
registry.register(new Scheme("https", sf, 443));
|
||||
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(registry);
|
||||
cm.setMaxTotal(Integer.parseInt(System.getProperty("zuul.max.host.connections",
|
||||
"200")));
|
||||
cm.setDefaultMaxPerRoute(Integer.parseInt(System.getProperty(
|
||||
"zuul.max.host.connections", "20")));
|
||||
return cm;
|
||||
}
|
||||
|
||||
private static void loadClient() {
|
||||
final HttpClient oldClient = CLIENT.get();
|
||||
CLIENT.set(newClient());
|
||||
if (oldClient != null) {
|
||||
CONNECTION_MANAGER_TIMER.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
oldClient.getConnectionManager().shutdown();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
log.error("error shutting down old connection manager", ex);
|
||||
}
|
||||
}
|
||||
}, 30000);
|
||||
}
|
||||
}
|
||||
|
||||
private static HttpClient newClient() {
|
||||
// I could statically cache the connection manager but we will probably want to
|
||||
// make some of its properties
|
||||
// dynamic in the near future also
|
||||
try {
|
||||
DefaultHttpClient httpclient = new DefaultHttpClient(newConnectionManager());
|
||||
HttpParams httpParams = httpclient.getParams();
|
||||
httpParams.setIntParameter(CoreConnectionPNames.SO_TIMEOUT,
|
||||
SOCKET_TIMEOUT.get());
|
||||
httpParams.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,
|
||||
CONNECTION_TIMEOUT.get());
|
||||
httpclient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0,
|
||||
false));
|
||||
httpParams.setParameter(ClientPNames.COOKIE_POLICY,
|
||||
org.apache.http.client.params.CookiePolicy.IGNORE_COOKIES);
|
||||
httpclient.setRedirectStrategy(new org.apache.http.client.RedirectStrategy() {
|
||||
@Override
|
||||
public boolean isRedirected(HttpRequest httpRequest,
|
||||
HttpResponse httpResponse, HttpContext httpContext) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.apache.http.client.methods.HttpUriRequest getRedirect(
|
||||
HttpRequest httpRequest, HttpResponse httpResponse,
|
||||
HttpContext httpContext) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return httpclient;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MySSLSocketFactory extends SSLSocketFactory {
|
||||
private SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
|
||||
public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException,
|
||||
KeyManagementException, KeyStoreException, UnrecoverableKeyException {
|
||||
super(truststore);
|
||||
TrustManager tm = new X509TrustManager() {
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType)
|
||||
throws CertificateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType)
|
||||
throws CertificateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
TrustManager[] tms = new TrustManager[1];
|
||||
tms[0] = tm;
|
||||
this.sslContext.init(null, tms, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
|
||||
throws IOException, UnknownHostException {
|
||||
return this.sslContext.getSocketFactory().createSocket(socket, host, port,
|
||||
autoClose);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket() throws IOException {
|
||||
return this.sslContext.getSocketFactory().createSocket();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add header names to exclude from proxied response in the current request.
|
||||
* @param names
|
||||
*/
|
||||
protected void addIgnoredHeaders(String... names) {
|
||||
helper.addIgnoredHeaders(names);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
package org.springframework.cloud.netflix.zuul.filters;
|
||||
|
||||
import org.apache.http.client.config.CookieSpecs;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.impl.client.BasicCookieStore;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.IntegrationTest;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.boot.test.TestRestTemplate;
|
||||
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
|
||||
import org.springframework.cloud.netflix.zuul.RoutesEndpoint;
|
||||
import org.springframework.cloud.netflix.zuul.ZuulProxyConfiguration;
|
||||
import org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import static junit.framework.TestCase.assertFalse;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = SampleCustomZuulProxyApplication.class)
|
||||
@WebAppConfiguration
|
||||
@IntegrationTest({"server.port: 0", "server.contextPath: /app"})
|
||||
@DirtiesContext
|
||||
public class CustomHostRoutingFilterTests {
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private int port;
|
||||
|
||||
@Autowired
|
||||
private ProxyRouteLocator routes;
|
||||
|
||||
@Autowired
|
||||
private RoutesEndpoint endpoint;
|
||||
|
||||
@Test
|
||||
public void getOnSelfViaCustomHostRoutingFilter() {
|
||||
this.routes.addRoute("/self/**", "http://localhost:" + this.port + "/app");
|
||||
this.endpoint.reset();
|
||||
ResponseEntity<String> result = new TestRestTemplate().getForEntity(
|
||||
"http://localhost:" + this.port + "/app/self/get/1", String.class);
|
||||
assertEquals(HttpStatus.OK, result.getStatusCode());
|
||||
assertEquals("Get 1", result.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postOnSelfViaCustomHostRoutingFilter() {
|
||||
this.routes.addRoute("/self/**", "http://localhost:" + this.port + "/app");
|
||||
this.endpoint.reset();
|
||||
MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
|
||||
params.add("id", "2");
|
||||
ResponseEntity<String> result = new TestRestTemplate().postForEntity(
|
||||
"http://localhost:" + this.port + "/app/self/post", params, String.class);
|
||||
assertEquals(HttpStatus.OK, result.getStatusCode());
|
||||
assertEquals("Post 2", result.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putOnSelfViaCustomHostRoutingFilter() {
|
||||
this.routes.addRoute("/self/**", "http://localhost:" + this.port + "/app");
|
||||
this.endpoint.reset();
|
||||
ResponseEntity<String> result = new TestRestTemplate().exchange(
|
||||
"http://localhost:" + this.port + "/app/self/put/3", HttpMethod.PUT,
|
||||
new HttpEntity<>((Void) null), String.class);
|
||||
assertEquals(HttpStatus.OK, result.getStatusCode());
|
||||
assertEquals("Put 3", result.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void patchOnSelfViaCustomHostRoutingFilter() {
|
||||
this.routes.addRoute("/self/**", "http://localhost:" + this.port + "/app");
|
||||
this.endpoint.reset();
|
||||
MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
|
||||
params.add("patch", "5");
|
||||
ResponseEntity<String> result = new TestRestTemplate().exchange(
|
||||
"http://localhost:" + this.port + "/app/self/patch/4", HttpMethod.PATCH,
|
||||
new HttpEntity<>(params), String.class);
|
||||
assertEquals(HttpStatus.OK, result.getStatusCode());
|
||||
assertEquals("Patch 45", result.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOnSelfIgnoredHeaders() {
|
||||
this.routes.addRoute("/self/**", "http://localhost:" + this.port + "/app");
|
||||
this.endpoint.reset();
|
||||
ResponseEntity<String> result = new TestRestTemplate().getForEntity(
|
||||
"http://localhost:" + this.port + "/app/self/get/1", String.class);
|
||||
assertEquals(HttpStatus.OK, result.getStatusCode());
|
||||
assertTrue(result.getHeaders().containsKey("X-NotIgnored"));
|
||||
assertFalse(result.getHeaders().containsKey("X-Ignored"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOnSelfWithSessionCookie() {
|
||||
this.routes.addRoute("/self/**", "http://localhost:" + this.port + "/app");
|
||||
this.endpoint.reset();
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
ResponseEntity<String> result1 = restTemplate.getForEntity(
|
||||
"http://localhost:" + this.port + "/app/self/cookie/1", String.class);
|
||||
|
||||
ResponseEntity<String> result2 = restTemplate.getForEntity(
|
||||
"http://localhost:" + this.port + "/app/self/cookie/2", String.class);
|
||||
|
||||
assertEquals("SetCookie 1", result1.getBody());
|
||||
assertEquals("GetCookie 1", result2.getBody());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@RestController
|
||||
class SampleCustomZuulProxyApplication {
|
||||
|
||||
@RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
|
||||
public String get(@PathVariable String id, HttpServletResponse response) {
|
||||
response.setHeader("X-Ignored", "foo");
|
||||
response.setHeader("X-NotIgnored", "bar");
|
||||
return "Get " + id;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/cookie/{id}", method = RequestMethod.GET)
|
||||
public String getWithCookie(@PathVariable String id, HttpSession session) {
|
||||
Object testCookie = session.getAttribute("testCookie");
|
||||
if (testCookie != null) {
|
||||
return "GetCookie " + testCookie;
|
||||
}
|
||||
session.setAttribute("testCookie", id);
|
||||
return "SetCookie " + id;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/post", method = RequestMethod.POST)
|
||||
public String post(@RequestParam("id") String id) {
|
||||
return "Post " + id;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/put/{id}", method = RequestMethod.PUT)
|
||||
public String put(@PathVariable String id) {
|
||||
return "Put " + id;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/patch/{id}", method = RequestMethod.PATCH)
|
||||
public String patch(@PathVariable String id, @RequestParam("patch") String patch) {
|
||||
return "Patch " + id + patch;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SampleCustomZuulProxyApplication.class, args);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableZuulProxy
|
||||
protected static class CustomZuulProxyConfig extends ZuulProxyConfiguration {
|
||||
@Bean
|
||||
@Override
|
||||
public SimpleHostRoutingFilter simpleHostRoutingFilter() {
|
||||
return new CustomHostRoutingFilter();
|
||||
}
|
||||
|
||||
private class CustomHostRoutingFilter extends SimpleHostRoutingFilter {
|
||||
|
||||
@Override
|
||||
public Object run() {
|
||||
super.addIgnoredHeaders("X-Ignored");
|
||||
return super.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CloseableHttpClient newClient() {
|
||||
// Custom client with cookie support.
|
||||
// In practice, we would want a custom cookie store using a multimap with a user key.
|
||||
return HttpClients.custom()
|
||||
.setConnectionManager(newConnectionManager())
|
||||
.setDefaultCookieStore(new BasicCookieStore())
|
||||
.setDefaultRequestConfig(RequestConfig.custom()
|
||||
.setCookieSpec(CookieSpecs.DEFAULT)
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user