javascript
Spring Cloud【Finchley】-18 Zuul过滤器
文章目錄
- 概述
- Filter Types
- Zuul 請求生命周期
- 示例
- Step1 新建模塊
- Step2 自定義zuul過濾器
- Step3 初始化zuul過濾器
- Step4 測試
- 禁用zuul過濾器
- 代碼
- 20190413更新
- Pre和Post過濾器(補充示例)
概述
前面幾篇博文,我們梳理了zuul的基本使用、路由及容錯.
我們知道,zuul包含了對請求的路由和過濾兩個功能,
- 路由功能負責將外部請求轉發到具體的微服務實例上,是實現外部訪問統一入口的基礎
- 過濾器功能則負責對請求的處理過程進行干預,是實現請求校驗、服務聚合等功能的基礎
每一個進入Zuul的HTTP請求都會經過一系列的過濾器處理鏈得到請求響應并返回給客戶端。
Spring Cloud官網中的介紹比較少 , https://cloud.spring.io/spring-cloud-static/Finchley.SR2/single/spring-cloud.html#_disable_zuul_filters
那我們就去zuul自己的官網上去看看吧 (這里我們看的是zuul1.x)
https://github.com/Netflix/zuul/wiki/How-it-Works
Filter Types
在Spring Cloud Zuul中實現的過濾器必須包含4個基本特征:
- 過濾類型
- 執行順序
- 執行條件
- 具體操作
我們通過zuul的源碼ZuulFilter來看下, ZuulFilter是一個抽象類,并且實現了IZuulFilter接口
IZuulFilter
- filterType:該函數需要返回一個字符串來代表過濾器的類型,而這個類型就是在HTTP請求過程中定義的各個階段。
在Zuul中默認定義了四種不同生命周期的過濾器類型,具體如下:
- filterOrder:通過int值來定義過濾器的執行順序,數值越小優先級越高。
- shouldFilter:返回一個boolean類型來判斷該過濾器是否要執行。我們可以通過此方法來指定過濾器的有效范圍。
- run:過濾器的具體邏輯。在該函數中,我們可以實現自定義的過濾邏輯,來確定是否要攔截當前的請求,不對其進行后續的路由,或是在請求路由返回結果之后,對處理結果做一些加工等。
Zuul 請求生命周期
Zuul默認定義了四個不同的過濾器類型,它們覆蓋了一個外部HTTP請求到達API網關,直到返回請求結果的全部生命周期.
下圖來自Zuul的官方WIKI中關于請求生命周期的圖解,它描述了一個HTTP請求到達API網關之后,如何在各個不同類型的過濾器之間流轉的詳細過程。
當外部HTTP請求到達API網關服務的時候,首先它會進入第一個階段pre,在這里它會被pre類型的過濾器進行處理,該類型的過濾器主要目的是在進行請求路由之前做一些前置加工,比如請求的校驗等
在完成了pre類型的過濾器處理之后,請求進入第二個階段routing,也就是之前說的路由請求轉發階段,請求將會被routing類型過濾器處理,這里的具體處理內容就是將外部請求轉發到具體服務實例上去的過程
當服務實例將請求結果都返回之后,routing階段完成,請求進入第三個階段post,此時請求將會被post類型的過濾器進行處理,這些過濾器在處理的時候不僅可以獲取到請求信息,還能獲取到服務實例的返回信息,所以在post類型的過濾器中,我們可以對處理結果進行一些加工或轉換等內容
還有一個特殊的階段error,該階段只有在上述三個階段中發生異常的時候才會觸發,但是它的最后流向還是post類型的過濾器,因為它需要通過post過濾器將最終結果返回給請求客戶端
示例
Step1 新建模塊
為了區分起見,我們在父工程下新建個module microservice-gateway-zuul-filter
pom.xml 及 application.yml 基本與https://github.com/yangshangwei/SpringCloudMaster/tree/master/microservice-gateway-zuul 相同
pom依賴
<!-- eureka client 依賴 . Eureka不是必須的 ,在沒有注冊中心的情況下,也可以使用zuul --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!-- zuul 依賴 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency>application.yml配置文件
server:port: 4536spring:application:name: microservice-gateway-zuul-filtereureka:client:service-url:defaultZone: http://artisan:artisan123@localhost:8761/eurekainstance:instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}#actuator 啟用所有的監控端點 “*”號代表啟用所有的監控端點,可以單獨啟用,例如,health,info,metrics # spring boot 升為 2.0 后,為了安全,默認 Actuator 只暴露了2個端點,heath 和 info management:endpoints:web:exposure:include: "*" endpoint:health:show-details: ALWAYSzuul: routes:microservice-provider-user: /userprovider/**logging:level:com.netflix: DEBUG # 將 com.netflix包的日志級別設置為debug,將打印zuul的轉發細節Step2 自定義zuul過濾器
package com.artisan.microservice.zuulFilter;import javax.servlet.http.HttpServletRequest;import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException;public class PreRequestZuulFilter extends ZuulFilter{@Overridepublic boolean shouldFilter() {return true;}@Overridepublic String filterType() {return "pre";}@Overridepublic int filterOrder() {return 0;}@Overridepublic Object run() throws ZuulException {HttpServletRequest request = RequestContext.getCurrentContext().getRequest();System.out.println("pre filter, 請求路徑:" +request.getRequestURI());return null;}}自定義的zuul過濾器,需要繼承 ZuulFilter,重寫如上方法
- filterType: 過濾器的類型,取值如下 pre route post error . 可以從源碼的注釋中看到
- filterOrder:過濾器的執行順序,不同的過濾器可以返回相同的數字
- shouldFilter:表示該過濾器是否要執行,true執行,false不執行
- run:過濾器的具體邏輯
Step3 初始化zuul過濾器
Step4 測試
- 啟動microservice-discovery-eureka
- 啟動micorservice-provider-user
- 啟動microservice-gateway-zuul-filter
- 訪問 http://localhost:4536/userprovider/user/2
觀察 microservice-gateway-zuul-filter的日志
禁用zuul過濾器
https://cloud.spring.io/spring-cloud-static/Finchley.SR2/single/spring-cloud.html#_disable_zuul_filters
spring cloud 默認為zuul編寫并啟用了一些過濾器 ,我們用的這個版本在 spring-cloud-netflix-zuul-2.0.0.RELEASE.jar 的org.springframework.cloud.netflix.zuul.filters 目錄下
禁用某個或某些過濾器,只需要 設置即可
舉個例子,比如上面自定義的zuul filter, 我們過想禁用的話,兩種方式
經測試,生效,日志中沒有打印run中的輸出。
代碼
https://github.com/yangshangwei/SpringCloudMaster/tree/master/microservice-gateway-zuul-filter
20190413更新
Pre和Post過濾器(補充示例)
package com.artisan.apigateway.filter;import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils;import javax.servlet.http.HttpServletRequest;import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;@Component public class TokenFilter extends ZuulFilter {@Overridepublic String filterType() {return PRE_TYPE;}@Overridepublic int filterOrder() {return PRE_DECORATION_FILTER_ORDER - 1;}@Overridepublic boolean shouldFilter() {return true;}@Overridepublic Object run() {RequestContext requestContext = RequestContext.getCurrentContext();HttpServletRequest request = requestContext.getRequest();//這里從url參數里獲取, 也可以從cookie, header里獲取String token = request.getParameter("token");if (StringUtils.isEmpty(token)) {requestContext.setSendZuulResponse(false);requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());}return null;} }返回值推薦使用FilterConstants類提供的常量
package com.artisan.apigateway.filter;import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletResponse;import java.util.UUID;import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.POST_TYPE; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SEND_RESPONSE_FILTER_ORDER;@Component public class AddResponseHeaderFilter extends ZuulFilter{@Overridepublic String filterType() {return POST_TYPE;}@Overridepublic int filterOrder() {return SEND_RESPONSE_FILTER_ORDER - 1;}@Overridepublic boolean shouldFilter() {return true;}@Overridepublic Object run() {RequestContext requestContext = RequestContext.getCurrentContext();HttpServletResponse response = requestContext.getResponse();response.setHeader("X-Foo", UUID.randomUUID().toString());return null;} }總結
以上是生活随笔為你收集整理的Spring Cloud【Finchley】-18 Zuul过滤器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring Cloud【Finchle
- 下一篇: Spring Boot2.x-07Spr