1、編寫Zuul過濾器(Java&Groovy)
理解過濾器類型和請求生命周期后,我們來編寫一個Zuul過濾器。編寫Zuul的過濾器非常簡單,我們只需繼承抽象類ZuulFilter,然后實現幾個抽象方法就可以了。
那么現在,我們來編寫一個簡單的Zuul過濾器,讓該過濾器打印請求日志。
(1) 復制項目microservice-gateway-zuul,將ArtifactId修改為microservice-gateway-zuul-filter。
(2) 編寫自定義Zuul過濾器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public
class
PreRequestLogFilter
extends
ZuulFilter {
private
static
final
Logger LOGGER = LoggerFactory.getLogger(PreRequestLogFilter.
class
);
@Override
public
String filterType() {
return
"pre"
;
}
@Override
public
int
filterOrder() {
return
1
;
}
@Override
public
boolean
shouldFilter() {
return
true
;
}
@Override
public
Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
PreRequestLogFilter.LOGGER.info(String.format(
"send %s request to %s"
, request.getMethod(), request.getRequestURL().toString()));
return
null
;
}
}
|
由代碼可知,自定義的Zuul Filter需實現以下幾個方法:
- filterType:返回過濾器的類型。有pre、route、post、error等幾種取值,分別對應上文的幾種過濾器。詳細可以參考
com.netflix.zuul.ZuulFilter.filterType()
中的注釋。 - filterOrder:返回一個int值來指定過濾器的執行順序,不同的過濾器允許返回相同的數字。
- shouldFilter:返回一個boolean值來判斷該過濾器是否要執行,true表示執行,false表示不執行。
- run:過濾器的具體邏輯。本例中,我們讓它打印了請求的HTTP方法以及請求的地址。
(2) 修改啟動類,為啟動類添加以下內容:
1
2
3
4
|
@Bean
public
PreRequestLogFilter preRequestLogFilter() {
return
new
PreRequestLogFilter();
}
|
3、測試Zuul過濾器
(1) 啟動microservice-discovery-eureka。
(2) 啟動microservice-provider-user。
(3) 啟動microservice-gateway-zuul-filter。
(4) 訪問http://localhost:8040/microservice-provider-user/1 ,可獲得類似如下的日志。
1
|
[nio-
8040
-exec-
6
] c.i.c.s.filters.pre.PreRequestLogFilter : send GET request to http:
//localhost:8040//microservice-provider-user/1
|
說明我們編寫的自定義Zuul過濾器被執行了。
4、禁用Zuul過濾器
Spring Cloud默認為Zuul編寫並啟用了一些過濾器,例如DebugFilter、FormBodyWrapperFilter、PreDecorationFilter等。這些過濾器都存放在spring-cloud-netflix-core這個Jar包的org.springframework.cloud.netflix.zuul.filters包中。
一些場景下,我們想要禁用掉部分過濾器,此時該怎么辦呢?
答案非常簡單,只需設置zuul.<SimpleClassName>.<filterType>.disable=true
,即可禁用SimpleClassName所對應的過濾器。
以過濾器org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter
為例,只需設置zuul.SendResponseFilter.post.disable=true
,即可禁用該過濾器。
5、幾個過濾器的例子
5.1、根據用戶名來過濾
通過繼承ZuulFilter然后覆寫上面的4個方法,實現一個簡單的過濾器:
filterType:返回一個字符串代表過濾器的類型,在zuul中定義了四種不同生命周期的過濾器類型,具體如下:
pre
:可以在請求被路由之前調用route
:在路由請求時候被調用post
:在route和error過濾器之后被調用error
:處理請求時發生錯誤時被調用
Zuul的主要請求生命周期包括“pre”,“route”和“post”等階段。對於每個請求,都會運行具有這些類型的所有過濾器。
filterOrder
:通過int值來定義過濾器的執行順序
shouldFilter
:返回一個boolean類型來判斷該過濾器是否要執行,所以通過此函數可實現過濾器的開關。在上例中,我們直接返回true,所以該過濾器總是生效
run
:過濾器的具體邏輯。需要注意,這里我們通過ctx.setSendZuulResponse(false)
令zuul過濾該請求,不對其進行路由,然后通過ctx.setResponseStatusCode(401)
設置了其返回的錯誤碼
過濾器間的協調
過濾器沒有直接的方式來訪問對方。 它們可以使用RequestContext共享狀態,這是一個類似Map的結構,具有一些顯式訪問方法用於被認為是Zuul的原語,內部是使用ThreadLocal實現的。