参考地址:https://www.cnblogs.com/linjiqin/p/10202085.html
zuul网关中根据过滤器的生命周期有以下类型的过滤器:
a、pre: 这种过滤器在请求被路由之前调用。可利用这种过滤器实现身份验证、在集群中选择请求的微服务,记录调试信息等。
b、routing: 这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用apache httpclient或netflix ribbon请求微服务。
c、post: 这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的http header、收集统计信息和指标、将响应从微服务发送给客户端等。
e、error: 在其他阶段发送错误时执行该过滤器。
除了默认的过滤器类型,zuul还允许创建自定义的过滤器类型。例如,可以定制一种static类型的过滤器,直接在zuul中生成响应,而不将请求转发到后端的微服务。
zuul请求的生命周期如下图,该图详细描述了各种类型的过滤器的执行顺序。
1、自定义pre过滤器@Component@Slf4j
public class MyZuulFilter extends ZuulFilter {
//过滤器类型
@Override
public String filterType() {
return "pre";
}
//zuul-core中的FilterLoader.java的getFilterByType中按类型pre、route、post取Filter后,再按照FilterOrder进行排序。
//先执行pre>routing>post 然后再在同类型的过滤器按照order大小执行,越小的越先被执行
@Override
public int filterOrder() {
return 0;
}
//过滤器是否执行,false不执行
@Override
public boolean shouldFilter() {
return true;
}
//自定义执行逻辑
@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
log.info("自定义zuulFilter:" + request.getRequestURI());
return null;
}
}
2、自定义error过滤器
/**
* @classname: MyErrorFilter
* @desc: 异常过滤器:当请求发送异常时,调用该过滤器
* @author: YZ
* @date: 2020/5/26 14:14
* @version: 1.0
**/
@Component
@Slf4j
public class MyErrorFilter extends SendErrorFilter {
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
ZuulException e = (ZuulException) findZuulException(ctx.getThrowable()).getThrowable();
log.error("请求失败:", e);
ctx.remove("throwable");
ctx.set("message", e.getMessage());
return null;
}
}
3、自定义post过滤器
该过滤器只要设置为true,就一定会执行(即使执行了error过滤器),在这里实现结果统一封装返回。
1 /** 2 * @classname: MyErrorFilter 3 * @desc: 后置过滤器:检验请求是否成功 4 * @author: YZ 5 * @date: 2020/5/26 14:14 6 * @version: 1.0 7 **/ 8 @Component 9 @Slf4j 10 public class MyPostFilter extends ZuulFilter { 11 12 13 @Autowired 14 private SendResponseFilter sendResponseFilter; 15 16 @Override 17 public String filterType() { 18 return FilterConstants.POST_TYPE; 19 } 20 21 @Override 22 public int filterOrder() { 23 return FilterConstants.SEND_RESPONSE_FILTER_ORDER; 24 } 25 26 @Override 27 public boolean shouldFilter() { 28 return true; 29 } 30 31 @Override 32 public Object run() { 33 RequestContext ctx = RequestContext.getCurrentContext(); 34 HttpServletResponse response = ctx.getResponse(); 35 //只处理非200 36 if (response.getStatus() != HttpStatus.OK.value()) { 37 if (response.getStatus() != HttpStatus.UNAUTHORIZED.value()) { 38 //返回状态非401的都改为200 39 response.setStatus(HttpStatus.OK.value()); 40 } 41 response.setHeader("Content-Type", "application/json"); 42 Object message = ctx.get("message"); 43 InputStream is; 44 InputStreamReader ir; 45 BufferedReader streamReader; 46 List<Closeable> closeables = null; 47 String msg = null; 48 try (OutputStream out = response.getOutputStream()) { 49 if (null != message) { 50 msg = message.toString(); 51 } else { 52 closeables = new ArrayList<>(3); 53 is = ctx.getResponseDataStream(); 54 closeables.add(is); 55 ir = new InputStreamReader(is); 56 closeables.add(ir); 57 streamReader = new BufferedReader(ir); 58 closeables.add(streamReader); 59 60 StringBuilder respomseStrBuilder = new StringBuilder(); 61 String inputStr = ""; 62 while ((inputStr = streamReader.readLine()) != null) { 63 respomseStrBuilder.append(inputStr); 64 } 65 JSONObject jsonObject = JSONObject.parseObject(respomseStrBuilder.toString()); 66 JSONArray errors; 67 //获取错误信息 68 if (null != (errors = jsonObject.getJSONArray("errors"))) { 69 String defaultMessage = errors.getJSONObject(0).getString("defaultMessage"); 70 if (null != defaultMessage) { 71 msg = defaultMessage; 72 } 73 } 74 if (null == msg) { 75 msg = jsonObject.getString("message"); 76 } 77 if (null == msg) { 78 msg = jsonObject.getString("error_description"); 79 } 80 log.error("请求失败:{}", msg); 81 } 82 IOUtils.write(JSON.toJSONString(ResponseData.failed("请求失败:" + msg)).getBytes(StandardCharsets.UTF_8), out); 83 } catch (IOException e) { 84 log.error("请求失败:", e); 85 } finally { 86 //关闭流 87 if (!CollectionUtil.isEmpty(closeables)) { 88 closeables.forEach(closeable -> { 89 if (null != closeable) { 90 try { 91 closeable.close(); 92 } catch (IOException e) { 93 } 94 } 95 }); 96 } 97 } 98 } else { 99 //使用默认的post拦截器 100 sendResponseFilter.run(); 101 } 102 return null; 103 } 104 105 }
4、禁用zuul默认的过滤器
即使自定义了过滤器,如果不经用zuul的默认过滤器,默认过滤器也会被执行,造成结果被篡改。
禁用语法:zuul.filter名称.disable=true
#禁用指定过滤器
zuul:
SendResponseFilter:
post:
disable: true
SendErrorFilter:
error:
disable: true