zuul的工作原理
zuul的底层是通过各种Filter来实现的,zuul中的filter按照执行顺序分为了“pre”前置(”custom”自定义一般是前置),“routing”路由,“post”后置,以及“error”异常Filter组成,当各种Filter出现了异常,请求会跳转到“error filter”,然后再经过“post filter” 最后返回结果,下面是Filter的执行流程图:
- 正常流程:
- 请求到达首先会经过pre类型过滤器,而后到达routing类型,进行路由,请求就到达真正的服务提供者,执行请求,返回结果后,会到达post过滤器。而后返回响应。
- 异常流程:
- 整个过程中,pre或者routing过滤器出现异常,都会直接进入error过滤器,再error处理完毕后,会将请求交给POST过滤器,最后返回给用户。
- 如果是error过滤器自己出现异常,最终也会进入POST过滤器,而后返回。
- 如果是POST过滤器出现异常,会跳转到error过滤器,但是与pre和routing不同的时,请求不会再到达POST过滤器了。
ZuulFilter
Zuul提供了一个抽象的Filter:ZuulFilter我们可以通过该抽象类来自定义Filter,该Filter有四个核心方法
public abstract class ZuulFilter implements IZuulFilter{
//filterType :是用来指定filter的类型的(类型见常量类:FilterConstants)
abstract public String filterType();
//filterOrder :是filter的执行顺序,越小越先执行
abstract public int filterOrder();
//shouldFilter :是其父接口IZuulFilter的方法,用来决定run方法是否要被执行
boolean shouldFilter();
//run :是其父接口IZuulFilter的方法,该方法是Filter的核心业务方法
Object run() throws ZuulException;
}
自定义Filter
在Zuul层实现统一的登录检查:如果请求头中有“token”属性,我们就认为已经登录成功,可以继续往下游的服务执行,否则就视为请求未登录,直接返回错误信息,这一需求需要自定义Filter继承ZuulFilter类来实现
/**
* LoginCheckFilter做登录检查
*/
@Component
public class LoginCheckFilter extends ZuulFilter{
@Override
public String filterType() {
return "pre"; //路由类型
}
@Override
public int filterOrder() {
return 0; // 执行等级
}
@Override
public boolean shouldFilter() { // TRUE执行下面的run方法,false不执行
// 判断哪些路径放行
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
if (request.getRequestURI().contains("/login") || request.getRequestURI().contains("/register")){
return false;
}
return true;
}
@Override
public Object run() throws ZuulException { // 是否放行是根据currentContext.setSendZuulResponse(false) 默认为TRUE
// 1获取request请求对象
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
HttpServletResponse response = currentContext.getResponse();
// 设置响应字符集
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
// 2获取请求头中的请求头
String token = request.getHeader("token");
// 3判断token是否存在,不存在返回错误信息,存在就放行
if(!StringUtils.hasLength(token)){
try {
currentContext.setSendZuulResponse(false); // 设置拦截
response.getWriter().write("请登录后重试!!");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return null;
}
}
- 在 filterType方法中我们返回“pre”前置filter的常量,让他成为前置filter(登录检查需要在请求的最前面来做)
- 在filterOrder方法中返回的顺序值是 0 ,执行顺序越小越先执行
- 在shouldFilter方法中通过判断请求的url来决定是否需要做登录检查,返回true就是要做然后才会执行run方法
- 在run方法中我们通过获取请求头中的token判断是否登录,如果没登录就返回错误信息,阻止继续执行。
- RequestContext.getCurrentContext() 是一个Zuul提供的请求上下文对象