我们的项目里通过zuul实现路由转发,前几日接到这么一个需求,需要实现所有接口对于带指定前缀和不带前缀的url均能兼容访问,网上这方面的文档并不多,因此为了处理这个需求,捎带着阅读了一下zuul的部分源码
首先说一下结论,zuul本身便实现了这个功能,对于带/zuul的前缀的url会自动去掉该前缀进行转发,完美匹配这次需求。
接着开始理解源码,看一看zuul是怎么实现的。
在springboot项目中使用zuul需要使用@EnableZuulServer或@EnableZuulProxy中的至少一个注解。其中@EnableZuulServer对应ZuulServerAutoConfiguration,@EnableZuulProxy对应ZuulProxyAutoConfiguration,ZuulServerAutoConfiguration是ZuulProxyAutoConfiguration的父类,因此可以简单理解成@EnableZuulServer是@EnableZuulProxy的一个简化版本。
如下图:EnableZuulServer --> ZuulServerMarkerConfiguration --> ZuulServerAutoConfiguration,EnableZuulProxy也类似。
在这里主要针对EnableZuulProxy展开,我们开一下zuul是怎么针对请求的url进行处理的。
在ZuulProxyAutoConfiguration类中,我们注入了PreDecorationFilter进行拦截。
// pre filters
@Bean
public PreDecorationFilter preDecorationFilter(RouteLocator routeLocator, ProxyRequestHelper proxyRequestHelper) {
return new PreDecorationFilter(routeLocator, this.server.getServlet().getServletPrefix(), this.zuulProperties,
proxyRequestHelper);
}
进入这个类我们可以看到该filter的类型是pre,如果已经处理过转发逻辑的请求在不在拦截处理。
@Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER; //5
}
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
return !ctx.containsKey(FORWARD_TO_KEY) // a filter has already forwarded
&& !ctx.containsKey(SERVICE_ID_KEY); // a filter has already determined serviceId
}
接下来我们进入run方法仔细了解PreDecorationFilter的拦截逻辑。
@Override
public Object run() {
//1.根据请求的url找到对应的路由Route
RequestContext ctx = RequestContext.getCurrentContext();
final String requestURI = this.urlPathHelper.getPathWithinApplication(ctx.getRequest());
Route route = this.routeLocator.getMatchingRoute(requestURI);
//2.根据Route进行相应的转发
if (route != null) {
String location = route.getLocation();
if (location != null) {
ctx.put(REQUEST_URI_KEY, route.getPath());
ctx.put(PROXY_KEY, route.getId());
if (!route.isCustomSensitiveHeaders()) {
this.proxyRequestHelper
.addIgnoredHeaders(this.properties.getSensitiveHeaders().toArray(new String[0]));
}
else {
this.proxyRequestHelper.addIgnoredHeaders(rout