Spring Cloud Zuul過濾器介紹及使用

過濾器類型

Zuul 中的過濾器跟我們之前使用的 javax.servlet.Filter 不一樣,javax.servlet.Filter 只有一種類型,可以通過配置 urlPatterns 來攔截對應的請求。

而 Zuul 中的過濾器總共有 4 種類型,且每種類型都有對應的使用場景。

1)pre

可以在請求被路由之前調用。適用於身份認證的場景,認證通過後再繼續執行下面的流程。

2)route

在路由請求時被調用。適用於灰度發佈場景,在將要路由的時候可以做一些自定義的邏輯。

3)post

在 route 和 error 過濾器之後被調用。這種過濾器將請求路由到達具體的服務之後執行。適用於需要添加響應頭,記錄響應日誌等應用場景。

4)error

處理請求時發生錯誤時被調用。在執行過程中發送錯誤時會進入 error 過濾器,可以用來統一記錄錯誤信息。

請求生命週期

可以通過圖 1 看出整個過濾器的執行生命週期, 

過濾器生命週期
圖 1  過濾器生命週期


通過上面的圖可以清楚地知道整個執行的順序,請求發過來首先到 pre 過濾器,再到 routing 過濾器,最後到 post 過濾器,任何一個過濾器有異常都會進入 error 過濾器。

通過 com.netflix.zuul.http.ZuulServlet 也可以看出完整執行順序,ZuulServlet 類似 Spring-Mvc 的 DispatcherServlet,所有的 Request 都要經過 ZuulServlet 的處理。

ZuulServlet 源碼如下所示:


 
  1. @Override
  2. public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse)
  3. throws ServletException, IOException {
  4. try {
  5. init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
  6. RequestContext context = RequestContext.getCurrentContext();
  7. context.setZuulEngineRan();
  8. try {
  9. preRoute();
  10. } catch (ZuulException e) {
  11. error(e);
  12. postRoute();
  13. return;
  14. }
  15. try {
  16. route();
  17. } catch (ZuulException e) {
  18. error(e);
  19. postRoute();
  20. return;
  21. }
  22. try {
  23. postRoute();
  24. } catch (ZuulException e) {
  25. error(e);
  26. return;
  27. }
  28. } catch (Throwable e) {
  29. error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
  30. } finally {
  31. RequestContext.getCurrentContext().unset();
  32. }
  33. }

使用過濾器

我們創建一個 pre 過濾器,來實現 IP 黑名單的過濾操作,代碼如下所示。


 
  1. public class IpFilter extends ZuulFilter {
  2.  
  3. // IP黑名單列表
  4. private List<String> blackIpList = Arrays.asList("127.0.0.1");
  5.  
  6. public IpFilter() {
  7. super();
  8. }
  9.  
  10. @Override
  11. public boolean shouldFilter() {
  12. return true
  13. }
  14.  
  15. @Override
  16. public String filterType() {
  17. return "pre";
  18. }
  19.  
  20. @Override
  21. public int filterOrder() {
  22. return 1;
  23. }
  24.  
  25. @Override
  26. public Object run() {
  27. RequestContext ctx = RequestContext.getCurrentContext();
  28. String ip = IpUtils.getIpAddr(ctx.getRequest());
  29. // 在黑名單中禁用
  30. if (StringUtils.isNotBlank(ip) && blackIpList.contains(ip)) {
  31.  
  32. ctx.setSendZuulResponse(false);
  33. ResponseData data = ResponseData.fail("非法請求 ", ResponseCode.NO_AUTH_CODE.getCode());
  34. ctx.setResponseBody(JsonUtils.toJson(data));
  35. ctx.getResponse().setContentType("application/json; charset=utf-8");
  36. return null;
  37. }
  38. return null;
  39. }
  40. }

由代碼可知,自定義過濾器需要繼承 ZuulFilter,並且需要實現下面幾個方法:

1)shouldFilter

是否執行該過濾器,true 爲執行,false 爲不執行,這個也可以利用配置中心來實現,達到動態的開啓和關閉過濾器。

2)filterType

過濾器類型,可選值有 pre、route、post、error。

3)filterOrder

過濾器的執行順序,數值越小,優先級越高。

4)run

執行自己的業務邏輯,本段代碼中是通過判斷請求的 IP 是否在黑名單中,決定是否進行攔截。blackIpList 字段是 IP 的黑名單,判斷條件成立之後,通過設置 ctx.setSendZuulResponse(false),告訴 Zuul 不需要將當前請求轉發到後端的服務了。通過 setResponseBody 返回數據給客戶端。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章