Spring Cloud學習(四)Zuul過濾器詳解
轉載自:http://www.itmuch.com/spring-cloud/zuul/spring-cloud-zuul-filter/
http://blog.didispace.com/spring-cloud-zuul-exception-2/
http://blog.didispace.com/spring-cloud-zuul-exception-3/
過濾器是Zuul的核心元件,本節來詳細討論Zuul的過濾器。
過濾器型別與請求生命週期
Zuul大部分功能都是通過過濾器來實現的。Zuul中定義了四種標準過濾器型別,這些過濾器型別對應於請求的典型生命週期。
(1) PRE:這種過濾器在請求被路由之前呼叫。可利用這種過濾器實現身份驗證、在叢集中選擇請求的微服務、記錄除錯資訊等。
(2) ROUTING:這種過濾器將請求路由到微服務。這種過濾器用於構建傳送給微服務的請求,並使用Apache HttpClient或Netfilx Ribbon請求微服務。
(3) POST:這種過濾器在路由到微服務以後執行。這種過濾器可用來為響應新增標準的HTTP Header、收集統計資訊和指標、將響應從微服務傳送給客戶端等。
(4) ERROR:在其他階段發生錯誤時執行該過濾器。
除了預設的過濾器型別,Zuul還允許我們建立自定義的過濾器型別。例如,可以定製一種STATIC型別的過濾器,直接在Zuul中生成響應,而不將請求轉發到後端的微服務。
Zuul請求的生命週期如圖所示,該圖詳細描述了各種型別的過濾器的執行順序。
com.netflix.zuul.http.ZuulServlet
的service方法實現也可以看出,Zuul處理外部請求過程時,各個型別過濾器的執行邏輯:
try { preRoute(); } catch (ZuulException e) { error(e); postRoute(); return; } try { route(); } catch (ZuulException e) { error(e); postRoute(); return; } try { postRoute(); } catch (ZuulException e) { error(e); return; }
從程式碼中可以看到三個try-catch塊,它們依次分別代表了pre、route、post三個階段的過濾器呼叫,在catch的異常處理中都會被error型別的過濾器進行處理。error型別的過濾器處理完畢之後,除了來自post階段的異常之外,都會再被post過濾器進行處理。
自定義Zuul過濾器
理解過濾器型別和請求生命週期後,來編寫一個Zuul過濾器。編寫Zuul的過濾器非常簡單,只需繼承抽象類ZuulFilter,然後實現幾個抽象方法就可以了。
示例程式碼,定義一個簡單的Zuul過濾器,它實現了在請求被路由之前檢查HttpServletRequest中是否有accessToken引數,若有就進行路由,若沒有就拒絕訪問,返回401 Unauthorized錯誤。
@Component
public class AccessFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(AccessFilter.class);
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info("send {} request to {}", request.getMethod(), request.getRequestURL().toString());
Object accessToken = request.getParameter("accessToken");
if (accessToken == null) {
log.warn("access token is empty");
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
ctx.setResponseBody("miss token");
return null;
}
log.info("access token ok");
return null;
}
}
在上面實現的過濾器程式碼中,通過繼承ZuulFilter抽象類並重寫了下面的四個方法來實現自定義的過濾器。這四個方法分別定義了:
filterType
:過濾器的型別,它決定過濾器在請求的哪個生命週期中執行。這裡定義為pre,代表會在請求被路由之前執行。詳細可以參考com.netflix.zuul.ZuulFilter.filterType()
中的註釋。filterOrder
:過濾器的執行順序。當請求在一個階段中存在多個過濾器時,需要根據該方法返回的值來依次執行。shouldFilter
:判斷該過濾器是否需要被執行。這裡直接返回了true,因此該過濾器對所有請求都會生效。實際運用中可以利用該函式來指定過濾器的有效範圍。run
:過濾器的具體邏輯。這裡通過ctx.setSendZuulResponse(false)
令zuul過濾該請求,不對其進行路由。
Zuul預設過濾器
Spring Cloud Zuul自帶的核心過濾器,例如DebugFilter
、FormBodyWrapperFilter
、PreDecorationFilter
等。這些過濾器都存放在spring-cloud-netflix-core
這個Jar包的org.springframework.cloud.netflix.zuul.filters
包中。具體的各類過濾器可以參看如下圖:
禁用Zuul過濾器
Spring Cloud預設為Zuul編寫並啟用了一些過濾器,一些場景下,想要禁用掉部分過濾器,此時該怎麼辦呢?只需設定zuul.<SimpleClassName>.<filterType>.disable=true
,即可禁用SimpleClassName
所對應的過濾器。以過濾器org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter
為例,只需設定zuul.SendResponseFilter.post.disable=true
,即可禁用該過濾器。