6Zuul 过滤器拦截顺序 · SpringCloud微服务实战 · 看云
6. Zuul 过滤器拦截顺序
导航
本节代码地址
GitHub: https://github.com/xuyisu/fw-sping-cloud/tree/master/fw-cloud-gateways/fw-cloud-gateways-zuul-simple
GitHub: https://github.com/xuyisu/fw-sping-cloud/tree/master/fw-cloud-ribbon/fw-cloud-ribbon-server
为了演示数据拦截顺序,我们再建一个新的过滤器
6.1 新建过滤器
新建一个过滤器,设置执行顺序为5,在TokenFilter之后,是不是这样,待会可以验证一下,这个过滤器是验证header中是否有name这个key,并且key的值要是zuul才能通过,否则失败。
@Slf4j
public class ZuulFilter extends com.netflix.zuul.ZuulFilter {
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 5;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info("我是ZuulFilter");
String token = request.getHeader("name");
if (StringUtils.isNotBlank(token) && token.equals("zuul")) {
ctx.setSendZuulResponse(true);
ctx.setResponseStatusCode(200);
ctx.set("code", 1);
} else {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
HttpServletResponse response = ctx.getResponse();
response.setHeader("content-type", "text/html;charset=utf8");
ctx.setResponseBody("请携带网关必须参数");
ctx.set("code", 0);
}
return null;
}
}
6.2 添加过滤器配置
@Bean
public ZuulFilter zuulFilter(){
return new ZuulFilter();
}
6.3 重启项目
浏览器或Postman输入localhost:8679/ribbon/user/1
首先全部设置正确的header
并且我们看到控制台输出的日志,确实是filterOrder越小越先执行
2020-01-04 18:14:11.379 INFO 10940 --- [nio-8679-exec-2] c.yisu.gateways.zuul.filter.TokenFilter : 我是TokenFilter
2020-01-04 18:14:11.385 INFO 10940 --- [nio-8679-exec-2] c.yisu.gateways.zuul.filter.ZuulFilter : 我是ZuulFilter
去掉token 验证
发现虽然验证失败,按理说应该不会执行第二个过滤器,但是执行了,看控制台日志
2020-01-04 18:23:49.714 INFO 10940 --- [nio-8679-exec-5] c.yisu.gateways.zuul.filter.TokenFilter : 我是TokenFilter
2020-01-04 18:23:49.715 INFO 10940 --- [nio-8679-exec-5] c.yisu.gateways.zuul.filter.ZuulFilter : 我是ZuulFilter
原因是什么呢?
Zuul中Filter的执行逻辑如下:在ZuuLServlet中的service方法
中执行对应的Filter,比如preRoute()。preRoute()中会通过zuulRunner来执行
首先请求经过ZuulServlet执行
@Override
public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
try {
init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
RequestContext context = RequestContext.getCurrentContext();
context.setZuulEngineRan();
try {
preRoute();
} catch (ZuulException e) {
error(e);
postRoute();
return;
}
try {
route();
} catch (ZuulException e) {
error(e);
postRoute();
return;
}
try {
postRoute();
} catch (ZuulException e) {
error(e);
return;
}
} catch (Throwable e) {
error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
} finally {
RequestContext.getCurrentContext().unset();
}
}
执行pre类型的过滤器
void preRoute() throws ZuulException {
zuulRunner.preRoute();
}
调用FilterProcessor的preRoute()
public void preRoute() throws ZuulException {
FilterProcessor.getInstance().preRoute();
}
然后preRoute()调用runFilters()获取所有过滤器并执行
public void preRoute() throws ZuulException {
try {
this.runFilters("pre");
} catch (ZuulException var2) {
throw var2;
} catch (Throwable var3) {
throw new ZuulException(var3, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + var3.getClass().getName());
}
}
public Object runFilters(String sType) throws Throwable {
if (RequestContext.getCurrentContext().debugRouting()) {
Debug.addRoutingDebug("Invoking {" + sType + "} type filters");
}
boolean bResult = false;
List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType);
if (list != null) {
for(int i = 0; i < list.size(); ++i) {
ZuulFilter zuulFilter = (ZuulFilter)list.get(i);
Object result = this.processZuulFilter(zuulFilter);
if (result != null && result instanceof Boolean) {
bResult |= (Boolean)result;
}
}
}
return bResult;
}
由此,可以知道为什么第一个报错了,为什么第二个过滤器也执行。
那么如何让第一个停了之后不执行第二个过滤器了呢?请看下一节数据传递

