Spencer Gibb
twitter: @spencerbgibb
email: sgibb@pivotal.io
Image credit http://microservices.io
Image credit http://microservices.io
@EnableZuulProxy
Include: spring-cloud-starter-zuul
Embedded or Dedicated
PreDecorationFilter
sets routeHost
key.
zuul:
routes:
stores:
url: http://localhost:8081
path: /stores/**
PreDecorationFilter
sets serviceId
key.
zuul:
routes:
test:
serviceId: testclient
path: /testing123/**
The default is Apache HttpClient
.
Set ribbon.okhttp.enabled=true
to use OkHttp 3 OkHttpClient
.
Set ribbon.restclient.enabled=true
to use deprecated Netflix RestClient
.
public class QueryParamPreFilter extends ZuulFilter {
public int filterOrder() {
// run before PreDecorationFilter
return PRE_DECORATION_FILTER_ORDER - 1;
}
public String filterType() {
return PRE_TYPE;
}
// continued...
}
public class QueryParamPreFilter extends ZuulFilter {
// continued from previous
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
if (request.getParameter("foo") != null) {
// put the serviceId in `RequestContext`
ctx.put(FilterConstants.SERVICE_ID_KEY,
request.getParameter("foo"));
}
return null;
}
}
Custom routing filters translate from:
public class OkHttpRoutingFilter extends ZuulFilter {
@Autowired
private ProxyRequestHelper helper;
public Object run() {
OkHttpClient httpClient = new OkHttpClient.Builder()
// customize
.build();
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
String method = request.getMethod();
String uri = this.helper.buildZuulRequestURI(request);
// continued...
}
}
public Object run() {
// continued from previous
// Translate headers from Servlet to OkHttp
Headers.Builder headers = new Headers.Builder();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
Enumeration<String> values = request.getHeaders(name);
while (values.hasMoreElements()) {
String value = values.nextElement();
headers.add(name, value);
}
}
// continued...
}
public Object run() {
// continued from previous
// Translate input stream
InputStream inputStream = request.getInputStream();
RequestBody requestBody = null;
if (inputStream != null && HttpMethod.permitsRequestBody(method)) {
MediaType mediaType = null;
if (headers.get("Content-Type") != null) {
mediaType = MediaType.parse(
(headers.get("Content-Type"));
}
requestBody = RequestBody.create(mediaType,
StreamUtils.copyToByteArray(inputStream));
}
// continued...
}
public Object run() {
// continued from previous
// Make request
Request.Builder builder = new Request.Builder()
.headers(headers.build())
.url(uri)
.method(method, requestBody);
Response response = httpClient.newCall(builder.build()).execute();
// continued...
}
public Object run() {
// continued from previous
// Make request
LinkedMultiValueMap<String, String> responseHeaders =
new LinkedMultiValueMap<>();
for (Map.Entry<String, List<String>> entry :
response.headers().toMultimap().entrySet()) {
responseHeaders.put(entry.getKey(), entry.getValue());
}
this.helper.setResponse(response.code(),
response.body().byteStream(),
responseHeaders);
// prevent SimpleHostRoutingFilter from running
context.setRouteHost(null);
return null; // ?!huh?
}
public class AddResponseHeaderFilter extends ZuulFilter {
public String filterType() {
return POST_TYPE;
}
public int filterOrder() {
return SEND_RESPONSE_FILTER_ORDER - 1;
}
public boolean shouldFilter() {
return true;
}
// continued
}
public class AddResponseHeaderFilter extends ZuulFilter {
// continued from previous
public Object run() {
RequestContext context = RequestContext.getCurrentContext();
HttpServletResponse servletResponse = context.getResponse();
servletResponse.addHeader("X-Foo",
UUID.randomUUID().toString());
return null;
}
}
http://techblog.netflix.com/2016/09/zuul-2-netflix-journey-to-asynchronous.html
In Spring Handler Mapping
spring.cloud.gateway.routes:
- id: a_crazy_route
uri: http://httpbin.org:80
predicates:
- Host=**.foo.org
- Url=/headers
- Method=GET
- Header=X-Request-Id, \d+
- Query=foo, ba.
- Query=baz
- Cookie=chocolate, ch.p
- After=1900-01-20T17:42:47.789-07:00[America/Denver]
DSL
@Bean
public RouteLocator customRouteLocator() {
return Routes.locator()
.route("test")
.uri("http://httpbin.org:80")
.predicate(host("**.abc.org").and(path("/image/png")))
.addResponseHeader("X-TestHeader", "foobar")
.and()
// more routes
.build();
}
Scoped for an individual Route
AddResponseHeader=X-Response-Foo, Bar
RemoveResponseHeader=X-Request-Foo
SecureHeaders
RewritePath=/foo/(?<part>.*), /$\{part}
RedirectTo=302, http://example.org
Hystrix=mycmd
github: https://github.com/spring-cloud-incubator/spring-cloud-gateway
blog: http://spencer.gibb.us
twitter: @spencerbgibb
email: sgibb@pivotal.io