參考地址: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