SpringCloud系列之網(wǎng)關(guān)gateway-8.過濾器原理和生命周期

過濾器的工作模式

所有開源框架實(shí)現(xiàn)過濾器的模式都是大同小異,通過一種類似職責(zé)鏈的方式,傳統(tǒng)的職責(zé)鏈模式中的事件會傳遞直到有一個(gè)處理對象接手,而過濾器和傳統(tǒng)的職責(zé)鏈有點(diǎn)不同,它更像是足球隊(duì)開場握手一樣,所有隊(duì)員一字排開,你要從頭到尾依次和所有球員握過手。

Gateway中的過濾器也是一樣的模型,他們經(jīng)過優(yōu)先級的排列,所有網(wǎng)關(guān)調(diào)用請求從最高優(yōu)先級的過濾器開始,一路走到頭,直到被最后一個(gè)過濾器處理。

過濾器的實(shí)現(xiàn)方式

在Gateway中實(shí)現(xiàn)一個(gè)過濾器非常簡單,只要實(shí)現(xiàn)GatewayFilter接口的默認(rèn)方法就好了

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 隨意發(fā)揮
return chain.filter(exchange);
}

這里面有兩個(gè)關(guān)鍵信息:

  • ServerWebExchange 這是Spring封裝的HTTP request-response交互協(xié)議,從中我們可以獲取request和response中的各種請求參數(shù),也可以向其中添加內(nèi)容
  • GatewayFilterChain 它是過濾器的調(diào)用鏈,在方法結(jié)束的時(shí)候我們需要將exchange對象傳入調(diào)用鏈中的下一個(gè)對象

過濾器的執(zhí)行階段

不同于Spring Cloud中上一代網(wǎng)關(guān)組件Zuul里對過濾器的Pre和Post的定義,Gateway是通過Filter中的代碼來實(shí)現(xiàn)類似Pre和Post的效果。
Pre和Post是指代當(dāng)前過濾器的執(zhí)行階段,Pre是在下一個(gè)過濾器之前被執(zhí)行,Post是在過濾器執(zhí)行過后再執(zhí)行。我們在Gateway Filter中也可以同時(shí)定義Pre和Post執(zhí)行邏輯。

Pre類型

我們就拿AddResponseHeaderGatewayFilterFactory舉例,它可以向Response中添加Header信息:

@Override
public GatewayFilter apply(NameValueConfig config) {
  return (exchange, chain) -> {
          exchange.getResponse().getHeaders().add(config.getName(), config.getValue());
    return chain.filter(exchange);
  };
}

這里的具體執(zhí)行方法是定義在調(diào)用“chain.filter()”方法之前,也就是在轉(zhuǎn)發(fā)到下級調(diào)用鏈路之前執(zhí)行的,因此可以理解為一個(gè)Pre類型的過濾器。

Post類型

我們拿SetStatusGatewayFilterFactory舉例,它在過濾器執(zhí)行完畢之后,將制定的HTTP status返回給調(diào)用方。

return chain.filter(exchange).then(Mono.fromRunnable(() -> {
    // 這里是業(yè)務(wù)邏輯
}));

這個(gè)過濾器的主要邏輯在then方法中,then是一個(gè)回調(diào)函數(shù),在下級調(diào)用鏈路都完成以后再執(zhí)行,因此這類過濾器可以看做是Post Filter。

過濾器排座次

在Gateway中我們可以通過實(shí)現(xiàn)org.springframework.core.Ordered接口,來給過濾器指定執(zhí)行順序,比如下面的代碼實(shí)現(xiàn)了Ordered接口方法,將過濾器執(zhí)行順序設(shè)置為0:

@Override
public int getOrder() {
  return 0;
}

Pre類型的過濾器來說,數(shù)字越大表示優(yōu)先級越高,也就越早被執(zhí)行。但對于Post類型的過濾器,則是數(shù)字越小越先被執(zhí)行。

注意:過濾器基本都在org.springframework.cloud.gateway.filter.factory包里

Header過濾器

這個(gè)系列有很多組過濾器,AddRequestHeader和AddResponseHeader,分別向Request和Response里加入指定Header。相應(yīng)的RemoveRequestHeader和RemoveResponseHeader分別做移除操作,用法也很簡單:

.filters(f -> f.addResponseHeader("who", "gateway-header"))

上面的例子會向header中添加一個(gè)who的屬性,對應(yīng)的值是gateway-header。

StripPrefix過濾器

這是個(gè)比較常用的過濾器,它的作用是去掉部分URL路徑。比如我們的過濾器配置如下:

.route(r -> r.path("/gateway-test/**")
.filters(f -> f.stripPrefix(1))
.uri("lb://FEIGN-SERVICE-PROVIDER/")
)

假如HTTP請求訪問的是
/gateway-test/sample/update
,如果沒有StripPrefix過濾器,那么轉(zhuǎn)發(fā)到FEIGN-SERVICE-PROVIDER服務(wù)的訪問路徑也是一樣的。當(dāng)我們添加了這個(gè)過濾器之后,Gateway就會根據(jù)“stripPrefix(1)”中的值截取URL中的路徑,比如這里我們設(shè)置的是1,那么就去掉一個(gè)前綴,最終發(fā)送給后臺服務(wù)的路徑變成了“/sample/update”

PrefixPath過濾器

它和StripPrefix的作用是完全相反的,會在請求路徑的前面加入前綴

.route(r -> r.path("/gateway-test/**")
.filters(f -> f.prefixPath("go"))
.uri("lb://FEIGN-SERVICE-PROVIDER/")
)

比如說我們訪問“/gateway-test/sample”的時(shí)候,上面例子中配置的過濾器就會把請求發(fā)送到“/go/gateway-test/sample”。

RedirectTo過濾器

它可以把收到特定狀態(tài)碼的請求重定向到一個(gè)指定網(wǎng)址:

.filters(f -> f.redirect(404, "https://www.imooc.com/"))

上面的例子接收HTTP status code和URL兩個(gè)參數(shù),如果請求結(jié)果是404,則重定向到第二個(gè)參數(shù)指定的頁面,這個(gè)功能也可以做統(tǒng)一異常處理,將Unauthorized或Forbidden請求重定向到登錄頁面。

SaveSession過濾器

我們知道微服務(wù)是無狀態(tài)的會話,所以大多都不依賴session機(jī)制,但是如果你有分布式session的需求,比如說某些功能是基于spring-session和spring-security來實(shí)現(xiàn)的,那么這個(gè)過濾器或許對你有用,它在調(diào)用服務(wù)之前都會強(qiáng)制保存session

.filters(f -> f.saveSession())
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容