spring-cloud Netflix 如何实现路由功能的
spring cloud 有很多有用的组件,其中就有大名鼎鼎的 Netflix。从官网截取了一段,看看 spring-cloud Netflix 到底能干嘛?
最后一行就涉及到了我们今天要说的路由过滤功能(Router and Filter)。
我们在使用zuul作为网关Filter的时候,一般所有转发或者重定向出去的地址 loation 都会被重写,原来的 host 会被替代。那么zuul是怎么做到的呢。请看下列代码:
@Configuration
@EnableZuulProxy
public class ZuulConfig {
@Bean
public LocationRewriteFilter locationRewriteFilter() {
return new LocationRewriteFilter();
}
}
原来zool是通过 LocationRewriteFilter 这个过滤器重写所有的请求地址。
源码截取如下:
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
Route route = routeLocator.getMatchingRoute(urlPathHelper.getPathWithinApplication(ctx.getRequest()));
if (route != null) {
Pair<String, String> lh = locationHeader(ctx);
if (lh != null) {
String location = lh.second();
URI originalRequestUri = UriComponentsBuilder
.fromHttpRequest(new ServletServerHttpRequest(ctx.getRequest()))
.build().toUri();
UriComponentsBuilder redirectedUriBuilder = UriComponentsBuilder.fromUriString(location);
UriComponents redirectedUriComps = redirectedUriBuilder.build();
//获取新地址
String newPath = getRestoredPath(this.zuulProperties, route,redirectedUriComps);
String modifiedLocation = redirectedUriBuilder.scheme(originalRequestUri.getScheme())
.host(originalRequestUri.getHost())
.port(originalRequestUri.getPort()).replacePath(newPath).build()
.toUriString();//用新的地址替换当前请求的地址。
lh.setSecond(modifiedLocation);
}
}
return null;
}
如果某些重定向地址不想被路由到怎么办?
那么我们可以改写一下 LocationRewriteFilter 的生效规则:
public class ExtendedLocationRewriteFilter extends LocationRewriteFilter {
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
int statusCode = ctx.getResponseStatusCode();
boolean isRedirect = ctx.getZuulResponseHeaders().contains(new Pair("isRedirect","true"));
return !isRedirect && HttpStatus.valueOf(statusCode).is3xxRedirection();
}
}
即在重定向的时候,在header里添加识别条件,然后 ExtendedLocationRewriteFilter 判断是否获取到此条件。
response.setHeader("isRedirect","true");