zuul实现模块异常统一拦截返回

参考地址: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 }
View Code

4、禁用zuul默认的过滤器

即使自定义了过滤器,如果不经用zuul的默认过滤器,默认过滤器也会被执行,造成结果被篡改。

禁用语法:zuul.filter名称.disable=true

#禁用指定过滤器
zuul:
  SendResponseFilter:
    post:
      disable: true
  SendErrorFilter:
    error:
      disable: true
原文地址:https://www.cnblogs.com/cq-yangzhou/p/13207260.html