歡迎訪問我的GitHub
https://github.com/zq2599/blog_demos
內容:所有原創文章分類彙總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等;
本篇概覽
作為《Spring Cloud Gateway實戰》系列的第五篇,是時候瞭解過濾器(filter)的作用了,本篇我們們一起來了解Spring Cloud Gateway內建好的過濾器,真是種類繁多功能強大
AddRequestHeader
- AddRequestHeader過濾器顧名思義,就是在請求頭部新增指定的內容
- 帶有predicate的完整配置:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
filters:
- AddRequestHeader=x-request-foo, bar-config
- 帶有predicate的完整動態配置:
[
{
"id": "path_route_addr",
"uri": "http://127.0.0.1:8082",
"predicates": [
{
"name": "Path",
"args": {
"pattern": "/hello/**"
}
}
],
"filters": [
{
"name": "AddRequestHeader",
"args": {
"name": "x-request-foo",
"value": "bar-dynamic"
}
}
]
}
]
- 實際效果:
AddRequestParameter
- AddRequestParameter過濾器顧名思義,就是新增請求引數
- 配置如下,服務提供方收到的請求中會多一個引數,名為foo,值為bar-config:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
filters:
- AddRequestParameter=foo, bar-config
- 帶有predicate的完整動態配置:
[
{
"id": "path_route_addr",
"uri": "http://127.0.0.1:8082",
"predicates": [
{
"name": "Path",
"args": {
"pattern": "/hello/**"
}
}
],
"filters": [
{
"name": "AddRequestParameter",
"args": {
"name": "foo",
"value": "bar-dynamic"
}
}
]
}
]
- 實際效果:
AddResponseHeader
- AddResponseHeader過濾器就是在響應的header中新增引數
- 配置如下,客戶端收到的響應,其header中會多一個引數,名為foo,值為bar-config-response:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
filters:
- AddResponseHeader=foo, bar-config-response
- 帶有predicate的完整動態配置:
[
{
"id": "path_route_addr",
"uri": "http://127.0.0.1:8082",
"predicates": [
{
"name": "Path",
"args": {
"pattern": "/hello/**"
}
}
],
"filters": [
{
"name": "AddResponseHeader",
"args": {
"name": "foo",
"value": "bar-dynamic-response"
}
}
]
}
]
- 實際效果:
DedupeResponseHeader
- 服務提供方返回的response的header中,如果有的key出線了多個value(例如跨域場景下的Access-Control-Allow-Origin),DedupeResponseHeader過濾器可以將重複的value剔除調,剔除策略有三種:RETAIN_FIRST (保留第一個,預設), RETAIN_LAST(保留最後一個), RETAIN_UNIQUE(去重)
- 配置如下,指定了兩個header key的去重,策略是保留最後一個:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_LAST
DedupeResponseHeader
- 服務提供方返回的response的header中,如果有的key出線了多個value(例如跨域場景下的Access-Control-Allow-Origin),DedupeResponseHeader過濾器可以將重複的value剔除調,剔除策略有三種:RETAIN_FIRST (保留第一個,預設), RETAIN_LAST(保留最後一個), RETAIN_UNIQUE(去重)
- 配置如下,指定了兩個header key的去重,策略是保留最後一個:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_LAST
CircuitBreaker
- CircuitBreaker即斷路器,我們們在單獨的一篇中深入體驗這個強大的功能吧
FallbackHeaders
- FallbackHeaders一般和CircuitBreaker配合使用,來看下面的配置,發生斷路後,請求會被轉發FallbackHeaders去處理,此時FallbackHeaders會在header中指定的key上新增異常資訊:
spring:
cloud:
gateway:
routes:
- id: ingredients
uri: lb://ingredients
predicates:
- Path=//ingredients/**
filters:
- name: CircuitBreaker
args:
name: fetchIngredients
fallbackUri: forward:/fallback
- id: ingredients-fallback
uri: http://localhost:9994
predicates:
- Path=/fallback
filters:
- name: FallbackHeaders
args:
executionExceptionTypeHeaderName: Test-Header
MapRequestHeader
- MapRequestHeader用於header中的鍵值對複製,如下配置的意思是:如果請求header中有<font color="blue">Blue</font>就新增名為<font color="red">X-Request-Red</font>的key,其值和<font color="blue">Blue</font>的值一樣
- 配置如下,指定了兩個header key的去重,策略是保留最後一個:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
filters:
- MapRequestHeader=Blue, X-Request-Red
- 如下圖,請求header中有Blue:
- 再看服務提供方的日誌,顯示header中多了X-Request-Red:
- 如果請求的header中已經存在<font color="blue">X-Request-Red</font>會出現什麼情況呢?如下圖,我們們把<font color="blue">X-Request-Red</font>寫在請求header中:
- 在服務提供方打斷點,可以發現神奇的一幕,header中的所有key,對應的值其實都是集合,只是大多數情況下集合裡面只有一個元素,而MapRequestHeader新增的元素會被放入這個集合,不會影響原有內容:
PrefixPath
- PrefixPath很好理解,就是轉發到服務提供者的時候,給path加字首
- 例如我這邊服務提供者原始地址是<font color="blue">http://127.0.0.1:8082/hello/str</font>配置如下,如果我給閘道器配置PrefixPath=hello,那麼訪問閘道器的時候,請求路徑中就不需要<font color="blue">hello</font>了,配置如下:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/str
filters:
- PrefixPath=/hello
- 如下圖,請求路徑無需<font color="blue">hello</font>:
PreserveHostHeader
- PreserveHostHeader在轉發請求到服務提供者的時候,會保留host資訊(否則就只能由HTTP client來決定了)
- 先看不使用PreserveHostHeader的效果,如下圖,服務提供者收到的請求header中的host就是閘道器配置的資訊:
- 加上PreserveHostHeader試試,如下圖紅框,是真正的host資訊:
RequestRateLimiter
- RequestRateLimiter用於限流,涉及內容較多,就放在單獨的章節深入研究吧
RedirectTo
- RedirectTo的功能簡單直白:跳轉到指定位置,下面的配置中,uri欄位明顯是一個無效的地址,但請求還是會被RedirectTo轉發到指定位置去:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
uri: http://127.1.1.1:11111
predicates:
- Path=/hello/**
filters:
- RedirectTo=302, http://127.0.0.1:8082/hello/str
RemoveRequestHeader
- RemoveRequestHeader很好理解,刪除請求header中的指定值
- 下面的配置會刪除請求header中的foo:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
filters:
- RemoveRequestHeader=foo
RemoveResponseHeader
- RemoveResponseHeader刪除響應header中的指定值
- 下面的配置會刪除響應header中的foo:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
filters:
- RemoveResponseHeader=foo
RemoveRequestParameter
- RemoveRequestParameter 刪除請求引數中的指定引數
- 下面的配置會刪除請求引數中的foo:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
filters:
- RemoveRequestParameter=foo1
RewritePath
- RewritePath非常實用,將請求引數中的路徑做變換
- 下面的配置會將<font color="blue">/test/str</font>轉成<font color="blue">/hello/str</font>:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/test/**
filters:
- RewritePath=/test/?(?<segment>.*), /hello/$\{segment}
- 請求如下,可見path中的test會被閘道器修改成hello,變成正確的請求路徑:
RewriteLocationResponseHeader
- RewriteLocationResponseHeader用於改寫response中的location資訊
- 配置如下,一共是四個引數:stripVersionMode、locationHeaderName、hostValue、protocolsRegex
- 例如請求是<font color="blue">api.example.com/some/object/name</font>,response的location是<font color="blue">object-service.prod.example.net/v2/some/object/id</font>,最終會被下面的filter改寫為<font color="blue">api.example.com/some/object/id</font>
spring:
cloud:
gateway:
routes:
- id: rewritelocationresponseheader_route
uri: http://example.org
filters:
- RewriteLocationResponseHeader=AS_IN_REQUEST, Location, ,
- stripVersionMode的策略一共三種:
NEVER_STRIP:不執行
AS_IN_REQUEST :原始請求沒有vesion,就執行
ALWAYS_STRIP :固定執行
- Location用於替換host:port部分,如果沒有就是用Request中的host
- protocolsRegex用於匹配協議,如果匹配不上,name過濾器啥都不做
RewriteResponseHeader
- RewriteResponseHeader很好理解:修改響應header,引數有三個:header的key,匹配value的正規表示式,修改value的結果
- 下面的配置表示修改響應header中<font color="blue">X-Response-Red</font>這個key的value,找到password=xxx的內容,改成password=*
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/test/**
filters:
- RewriteResponseHeader=X-Response-Red, , password=[^&]+, password=***
SecureHeaders
- SecureHeaders會在響應的header中新增很多和安全相關的內容,配置如下:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
filters:
- SecureHeaders
- 響應如下,可見header中新增了很多資訊:
- 如果不想返回上圖中的某些內容,可以在配置檔案中關閉掉,如下圖紅框,x-frame-options和strict-transport-security兩項被設定為不返回了:
- 再試試,得到如下響應,可見x-frame-options和strict-transport-security都沒有返回:
SetPath
- SetPath配合predicates使用,下面的配置會將請求<font color="blue">/test/str</font>改成<font color="blue">/hello/str</font>,可見這個segment是在predicates中賦值的,然後再filters中拿來用:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
filter:
secure-headers:
disable:
- x-frame-options
- strict-transport-security
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/test/{segment}
filters:
- SetPath=/hello/{segment}
SetRequestHeader
- SetRequestHeader顧名思義,就是改寫請求的header,將指定key改為指定value,如果該key不存在就建立:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
filter:
secure-headers:
disable:
- x-frame-options
- strict-transport-security
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
filters:
- SetRequestHeader=X-Request-Red, Blue
- 和SetPath類似,SetRequestHeader也可以和predicates配合,在predicates中定義的變數可以用在SetRequestHeader中,如下所示,當請求是/hello/str的時候,header中X-Request-Red的值就是<font color="blue">Blue-str</font>:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
filter:
secure-headers:
disable:
- x-frame-options
- strict-transport-security
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/{segment}
filters:
- SetRequestHeader=X-Request-Red, Blue-{segment}
SetResponseHeader
- SetResponseHeader顧名思義,就是改寫響應的header,將指定key改為指定value,如果該key不存在就建立:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
filter:
secure-headers:
disable:
- x-frame-options
- strict-transport-security
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
filters:
- SetResponseHeader=X-Request-Red, Blue
SetStatus
- SetStatus很好理解:控制返回code,下面的設定會返回500:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
filters:
- SetStatus=500
- 測試效果如下圖,服務提供者的內容會正常返回,但是返回碼已經被改為500了:
- 如果您想用SetStatus修改返回碼,同時又不想丟掉真實的返回碼,可以增加如下配置,這樣真實的返回碼就被放在名為<font color="blue">original-status-header-name</font>的key中了:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
set-status:
original-status-header-name: aaabbbccc
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
filters:
- SetStatus=500
StripPrefix
- StripPrefix是個很常用的filter,例如請求是<font color="blue">/aaa/bbb/hello/str</font>,我們要想將其轉為<font color="blue">/hello/str</font>,用<font color="blue">StripPrefix=2</font>即可,前面兩級path都被刪掉了:
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
set-status:
original-status-header-name: aaabbbccc
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/aaa/**
filters:
- StripPrefix=2
- 如下圖,響應正常:
Retry
- 顧名思義,Retry就是重試,需要以下引數配合使用:
- retries:重試次數
- statuses:遇到什麼樣的返回狀態才重試,取值參考:org.springframework.http.HttpStatus
- methods:那些型別的方法會才重試(GET、POST等),取值參考:org.springframework.http.HttpMethod
- series:遇到什麼樣的series值才重試,取值參考:org.springframework.http.HttpStatus.Series
- exceptions:遇到什麼樣的異常才重試
- backoff:重試策略,由多個引數構成,例如firstBackoff
- 參考配置如下:
spring:
cloud:
gateway:
routes:
- id: retry_test
uri: http://localhost:8080/flakey
predicates:
- Host=*.retry.com
filters:
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY
methods: GET,POST
backoff:
firstBackoff: 10ms
maxBackoff: 50ms
factor: 2
basedOnPreviousValue: false
RequestSize
- RequestSize也很常用:控制請求大小,可以使用<font color="blue">KB</font>或者<font color="blue">MB</font>等單位,超過這個大小就會返回413錯誤(Payload Too Large),
spring:
cloud:
gateway:
routes:
- id: request_size_route
uri: http://localhost:8080/upload
predicates:
- Path=/upload
filters:
- name: RequestSize
args:
maxSize: 5000000
- 注意,如果沒有設定RequestSize,Spring Cloud Gateway預設的上限是<font color="red">5MB</font>
SetRequestHostHeader
- SetRequestHostHeader會修改請求header中的host值
- 下面的配置,會將請求header中的host改為<font color="blue">aaabbb</font>
server:
#服務埠
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
filters:
- name: SetRequestHostHeader
args:
host: aaabbb
- 在服務提供者的程式碼中打斷點,如下圖,可見host已經被改為<font color="blue">aaabbb</font>
ModifyRequestBody
ModifyRequestBody用於修改請求的body內容,這裡官方推薦用程式碼來配置,如下所示,請求body中原本是字串,結果被改成了Hello物件的例項:
@Bean public RouteLocator routes(RouteLocatorBuilder builder) { return builder.routes() .route("rewrite_request_obj", r -> r.host("*.rewriterequestobj.org") .filters(f -> f.prefixPath("/httpbin") .modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE, (exchange, s) -> return Mono.just(new Hello(s.toUpperCase())))).uri(uri)) .build(); } static class Hello { String message; public Hello() { } public Hello(String message) { this.message = message; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
ModifyResponseBody
- ModifyResponseBody與前面的ModifyRequestBody類似,官方建議用程式碼實現,下面的程式碼作用是將響應body的內容改為全部大寫:
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("rewrite_response_upper", r -> r.host("*.rewriteresponseupper.org")
.filters(f -> f.prefixPath("/httpbin")
.modifyResponseBody(String.class, String.class,
(exchange, s) -> Mono.just(s.toUpperCase()))).uri(uri))
.build();
}
TokenRelay
- 在使用第三方鑑權的時候,如OAuth2,用TokenRelay可以將第三方的token轉發到服務提供者那裡去:
spring:
cloud:
gateway:
routes:
- id: resource
uri: http://localhost:9000
predicates:
- Path=/resource
filters:
- TokenRelay=
- 記得還要新增jar包依賴<font color="blue">org.springframework.boot:spring-boot-starter-oauth2-client</font>
設定全域性filter
- 前面的例子中,所有filter都放在路由策略中,配合predicates一起使用的,如果您想配置全域性生效的filter,可以在配置檔案中做以下設定,下面的配置表示AddResponseHeader和PrefixPath會處理所有請求,和路由設定無關:
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Red, Default-Blue
- PrefixPath=/httpbin
- 至此,大部分內建過濾器我們們已經瞭解了,有幾個略微複雜的留待後面的章節深入學習
你不孤單,欣宸原創一路相伴
歡迎關注公眾號:程式設計師欣宸
微信搜尋「程式設計師欣宸」,我是欣宸,期待與您一同暢遊Java世界...
https://github.com/zq2599/blog_demos