點擊上方「陶陶技術筆記」關注我
回復「資料」獲取作者整理的大量學習資料!
來源:https://dwz.cn/WekIPxsq
1. How to Include Spring Cloud Gateway
2. Glossary
3. How It Works
4. Route Predicate Factories
5. GatewayFilter Factories
6. Global Filters
7. TLS / SSL
8. Configuration
9. Reactor Netty Access Logs
10. CORS Configuration
11. Actuator API
12. Developer Guide
該項目提供了一個建立在Spring Ecosystem之上的API網關,包括:Spring 5,Spring Boot 2和Project Reactor。Spring Cloud Gateway旨在提供一種簡單而有效的方式來對API進行路由,並為他們提供切面,例如:安全性,監控/指標 和彈性等。
1. 如何在工程中引用Spring Cloud Gateway要在項目中引入Spring Cloud Gateway,需要引用 group org.springframework.cloud 和 artifact id為spring-cloud-starter-gateway starter。
如果應用了該starter,但由於某種原因不希望啟用網關,請進行設置spring.cloud.gateway.enabled=false。
重要
Spring Cloud Gateway依賴Spring Boot和Spring Webflux提供的Netty runtime。它不能在傳統的Servlet容器中工作或構建為WAR
Route 路由:gateway的基本構建模塊。它由ID、目標URI、斷言集合和過濾器集合組成。如果聚合斷言結果為真,則匹配到該路由。
Predicate 斷言:這是一個Java 8 Function Predicate。輸入類型是 Spring Framework ServerWebExchange。這允許開發人員可以匹配來自HTTP請求的任何內容,例如Header或參數。
Filter 過濾器:這些是使用特定工廠構建的 Spring FrameworkGatewayFilter實例。所以可以在返回請求之前或之後修改請求和響應的內容。
3. 如何工作的Spring Cloud Gateway Diagram
客戶端向Spring Cloud Gateway發出請求。如果Gateway Handler Mapping確定請求與路由匹配,則將其發送到Gateway Web Handler。此handler通過特定於該請求的過濾器鏈處理請求。圖中filters被虛線劃分的原因是filters可以在發送代理請求之前或之後執行邏輯。先執行所有「pre filter」邏輯,然後進行請求代理。在請求代理執行完後,執行「post filter」邏輯。
注意
HTTP和HTTPS URI默認埠設置是80和443。
Spring Cloud Gateway將路由作為Spring WebFlux HandlerMapping基礎結構的一部分進行匹配。Spring Cloud Gateway包含許多內置的路由斷言Factories。這些斷言都匹配HTTP請求的不同屬性。多個路由斷言Factories可以通過 and 組合使用。
4.1 After 路由斷言 FactoryAfter Route Predicate Factory採用一個參數——日期時間。在該日期時間之後發生的請求都將被匹配。
application.yml
spring:
cloud:
gateway:
routes:
- id: after_route
uri: http:
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
Before Route Predicate Factory採用一個參數——日期時間。在該日期時間之前發生的請求都將被匹配。
application.yml.
spring:
cloud:
gateway:
routes:
- id: before_route
uri: http:
predicates:
- Before=2017-01-20T17:42:47.789-07:00[America/Denver]
Between 路由斷言 Factory有兩個參數,datetime1和datetime2。在datetime1和datetime2之間的請求將被匹配。datetime2參數的實際時間必須在datetime1之後。
application.yml.
spring:
cloud:
gateway:
routes:
- id: between_route
uri: http:
predicates:
- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
Cookie 路由斷言 Factory有兩個參數,cookie名稱和正則表達式。請求包含次cookie名稱且正則表達式為真的將會被匹配。
application.yml
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: http:
predicates:
- Cookie=chocolate, ch.p
Header 路由斷言 Factory有兩個參數,header名稱和正則表達式。請求包含次header名稱且正則表達式為真的將會被匹配。
application.yml.
spring:
cloud:
gateway:
routes:
- id: header_route
uri: http:
predicates:
- Header=X-Request-Id, \d+
Host 路由斷言 Factory包括一個參數:host name列表。使用Ant路徑匹配規則,.作為分隔符。
application.yml.
spring:
cloud:
gateway:
routes:
- id: host_route
uri: http:
predicates:
- Host=.somehost.org,.anotherhost.org
Method 路由斷言 Factory只包含一個參數: 需要匹配的HTTP請求方式
application.yml.
spring:
cloud:
gateway:
routes:
- id: method_route
uri: http:
predicates:
- Method=GET
所有GET請求都將被路由
4.8 Path 路由斷言 FactoryPath 路由斷言 Factory 有2個參數: 一個Spring PathMatcher表達式列表和可選matchOptionalTrailingSeparator標識 .
application.yml.
spring:
cloud:
gateway:
routes:
- id: host_route
uri: http://example.org
predicates:
- Path=/foo/{segment},/bar/{segment}
例如: /foo/1 or /foo/bar or /bar/baz的請求都將被匹配
URI 模板變量 (如上例中的 segment ) 將以Map的方式保存於ServerWebExchange.getAttributes() key為ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE. 這些值將在GatewayFilter Factories使用
可以使用以下方法來更方便地訪問這些變量。
Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);
String segment = uriVariables.get("segment");
Query 路由斷言 Factory 有2個參數: 必選項 param 和可選項 regexp.
application.yml.
spring:
cloud:
gateway:
routes:
- id: query_route
uri: http:
predicates:
- Query=baz
則包含了請求參數 baz的都將被匹配。
application.yml.
spring:
cloud:
gateway:
routes:
- id: query_route
uri: http:
predicates:
- Query=foo, ba.
如果請求參數裡包含foo參數,並且值匹配為ba. 表達式,則將會被路由,如:bar and baz
4.10 RemoteAddr 路由斷言 FactoryRemoteAddr 路由斷言 Factory的參數為 一個CIDR符號(IPv4或IPv6)字符串的列表,最小值為1,例如192.168.0.1/16(其中192.168.0.1是IP位址並且16是子網掩碼)。
application.yml.
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: http:
predicates:
- RemoteAddr=192.168.1.1/24
如果請求的remote address 為 192.168.1.10則將被路由
4.10.1 修改遠程地址的解析方式默認情況下,RemoteAddr 路由斷言 Factory使用傳入請求中的remote address。如果Spring Cloud Gateway位於代理層後面,則可能與實際客戶端IP位址不匹配。
可以通過設置自定義RemoteAddressResolver來自定義解析遠程地址的方式。Spring Cloud Gateway網關附帶一個非默認遠程地址解析程序,它基於X-Forwarded-For header, XForwardedRemoteAddressResolver.
XForwardedRemoteAddressResolver 有兩個靜態構造函數方法,採用不同的安全方法:
XForwardedRemoteAddressResolver::TrustAll返回一個RemoteAddressResolver,它始終採用X-Forwarded-for頭中找到的第一個IP位址。這種方法容易受到欺騙,因為惡意客戶端可能會為解析程序接受的「x-forwarded-for」設置初始值。
XForwardedRemoteAddressResolver::MaxTrustedIndex獲取一個索引,該索引與在Spring Cloud網關前運行的受信任基礎設施數量相關。例如,如果SpringCloudGateway只能通過haproxy訪問,則應使用值1。如果在訪問Spring Cloud Gateway之前需要兩個受信任的基礎架構躍點,那麼應該使用2。
給定以下的header值:
X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3
下面的maxTrustedIndex值將生成以下遠程地址:
Java 配置方式:
GatewayConfig.java
RemoteAddressResolver resolver = XForwardedRemoteAddressResolver
.maxTrustedIndex(1);
...
.route("direct-route",
r -> r.remoteAddr("10.1.1.1", "10.10.1.1/24")
.uri("https://downstream1")
.route("proxied-route",
r -> r.remoteAddr(resolver, "10.10.1.1", "10.10.1.1/24")
.uri("https://downstream2")
)
過濾器允許以某種方式修改傳入的HTTP請求或返回的HTTP響應。過濾器的作用域是某些特定路由。Spring Cloud Gateway包括許多內置的 Filter工廠。
5.1 AddRequestHeader GatewayFilter Factory採用一對名稱和值作為參數
application.yml.
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: http:
filters:
- AddRequestHeader=X-Request-Foo, Bar
對於所有匹配的請求,這將向下遊請求的頭中添加 x-request-foo:bar header
5.2 AddRequestParameter GatewayFilter Factory採用一對名稱和值作為參數
application.yml.
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: http:
filters:
- AddRequestParameter=foo, bar
對於所有匹配的請求,這將向下遊請求添加foo=bar查詢字符串
5.3 AddResponseHeader GatewayFilter Factory採用一對名稱和值作為參數
application.yml.
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: http:
filters:
- AddResponseHeader=X-Response-Foo, Bar
對於所有匹配的請求,這會將x-response-foo:bar頭添加到下遊響應的header中
5.4 Hystrix GatewayFilter FactoryHystrix 是Netflix開源的斷路器組件。Hystrix GatewayFilter允許你向網關路由引入斷路器,保護你的服務不受級聯故障的影響,並允許你在下遊故障時提供fallback響應。
要在項目中啟用Hystrix網關過濾器,需要添加對 spring-cloud-starter-netflix-hystrix的依賴 Spring Cloud Netflix.
Hystrix GatewayFilter Factory 需要一個name參數,即HystrixCommand的名稱。
application.yml.
spring:
cloud:
gateway:
routes:
- id: hystrix_route
uri: http:
filters:
- Hystrix=myCommandName
這將剩餘的過濾器包裝在命令名為「myCommandName」的HystrixCommand中。
hystrix過濾器還可以接受可選的fallbackUri 參數。目前,僅支持forward: 預設的URI,如果調用fallback,則請求將轉發到與URI匹配的控制器。
application.yml.
spring:
cloud:
gateway:
routes:
- id: hystrix_route
uri: lb:
predicates:
- Path=/consumingserviceendpoint
filters:
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: forward:/incaseoffailureusethis
- RewritePath=/consumingserviceendpoint, /backingserviceendpoint
當調用hystrix fallback時,這將轉發到/incaseoffailureusethis uri。注意,這個示例還演示了(可選)通過目標URI上的lb前綴,使用Spring Cloud Netflix Ribbon 客戶端負載均衡。
主要場景是使用fallbackUri 到網關應用程式中的內部控制器或處理程序。但是,也可以將請求重新路由到外部應用程式中的控制器或處理程序,如:
application.yml.
spring:
cloud:
gateway:
routes:
- id: ingredients
uri: lb:
predicates:
- Path=
filters:
- name: Hystrix
args:
name: fetchIngredients
fallbackUri: forward:/fallback
- id: ingredients-fallback
uri: http:
predicates:
- Path=/fallback
在本例中,gateway應用程式中沒有 fallback 實現,但是另一個應用程式中有一個接口實現,註冊為「http://localhost:9994」。
在將請求轉發到fallback的情況下,Hystrix Gateway過濾還支持直接拋出Throwable 。它被作為ServerWebExchangeUtils.HYSTRIX_EXECUTION_EXCEPTION_ATTR屬性添加到ServerWebExchange中,可以在處理網關應用程式中的fallback時使用。
對於外部控制器/處理程序方案,可以添加帶有異常詳細信息的header。可以在 FallbackHeaders GatewayFilter Factory section.中找到有關它的更多信息。
hystrix配置參數(如 timeouts)可以使用全局默認值配置,也可以使用Hystrix wiki中所述屬性進行配置。
要為上面的示例路由設置5秒超時,將使用以下配置:
application.yml.
hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds: 5000
FallbackHeaders允許在轉發到外部應用程式中的FallbackUri的請求的header中添加Hystrix異常詳細信息,如下所示:
application.yml.
spring:
cloud:
gateway:
routes:
- id: ingredients
uri: lb:
predicates:
- Path=
filters:
- name: Hystrix
args:
name: fetchIngredients
fallbackUri: forward:/fallback
- id: ingredients-fallback
uri: http:
predicates:
- Path=/fallback
filters:
- name: FallbackHeaders
args:
executionExceptionTypeHeaderName: Test-Header
在本例中,在運行HystrixCommand發生執行異常後,請求將被轉發到 localhost:9994應用程式中的 fallback終端或程序。異常類型、消息(如果可用)cause exception類型和消息的頭,將由FallbackHeaders filter添加到該請求中。
通過設置下面列出的參數值及其默認值,可以在配置中覆蓋headers的名稱:
executionExceptionTypeHeaderName ("Execution-Exception-Type")
executionExceptionMessageHeaderName ("Execution-Exception-Message")
rootCauseExceptionTypeHeaderName ("Root-Cause-Exception-Type")
rootCauseExceptionMessageHeaderName ("Root-Cause-Exception-Message")
5.6 PrefixPath GatewayFilter FactoryPrefixPath GatewayFilter 只有一個 prefix 參數.
application.yml.
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: http:
filters:
- PrefixPath=/mypath
這將給所有匹配請求的路徑加前綴/mypath。因此,向/hello發送的請求將發送到/mypath/hello。
5.7 PreserveHostHeader GatewayFilter Factory該filter沒有參數。設置了該Filter後,GatewayFilter將不使用由HTTP客戶端確定的host header ,而是發送原始host header 。
application.yml.
spring:
cloud:
gateway:
routes:
- id: preserve_host_route
uri: http:
filters:
- PreserveHostHeader
RequestRateLimiter使用RateLimiter實現是否允許繼續執行當前請求。如果不允許繼續執行,則返回HTTP 429 - Too Many Requests (默認情況下)。
這個過濾器可以配置一個可選的keyResolver 參數和rate limiter參數(見下文)。
keyResolver 是 KeyResolver 接口的實現類.在配置中,按名稱使用SpEL引用bean。#{@myKeyResolver} 是引用名為'myKeyResolver'的bean的SpEL表達式。
KeyResolver.java.
public interface KeyResolver {
Mono<String> resolve(ServerWebExchange exchange);
}
KeyResolver接口允許使用可插拔策略來派生限制請求的key。在未來的裡程碑版本中,將有一些KeyResolver實現。
KeyResolver的默認實現是PrincipalNameKeyResolver,它從ServerWebExchange檢索Principal並調用Principal.getName()。
默認情況下,如果KeyResolver 沒有獲取到key,請求將被拒絕。此行為可以使用 spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key (true or false) 和 spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code屬性進行調整。
說明
無法通過"shortcut" 配置RequestRateLimiter。以下示例無效
application.properties.
spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2,
Redis的實現基於 Stripe實現。它需要使用 spring-boot-starter-data-redis-reactive Spring Boot starter。
使用的算法是Token Bucket Algorithm.。
redis-rate-limiter.replenishRate是你允許用戶每秒執行多少請求,而丟棄任何請求。這是令牌桶的填充速率。
redis-rate-limiter.burstCapacity是允許用戶在一秒鐘內執行的最大請求數。這是令牌桶可以保存的令牌數。將此值設置為零將阻止所有請求。
穩定速率是通過在replenishRate 和 burstCapacity中設置相同的值來實現的。可通過設置burstCapacity高於replenishRate來允許臨時突發流浪。在這種情況下,限流器需要在兩次突發之間留出一段時間(根據replenishRate),因為連續兩次突發將導致請求丟失 (HTTP 429 - Too Many Requests)。
application.yml.
spring:
cloud:
gateway:
routes:
- id: requestratelimiter_route
uri: http:
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
Config.java.
@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}
這定義了每個用戶10個請求的限制。允許20個突發,但下一秒只有10個請求可用。KeyResolver是一個簡單的獲取user請求參數的工具(注意:不建議用於生產)。
限流器也可以定義為RateLimiter接口的實現 bean。在配置中,按名稱使用SpEL引用bean。#{@myRateLimiter}是引用名為'myRateLimiter'的bean的SpEL表達式。
application.yml.
spring:
cloud:
gateway:
routes:
- id: requestratelimiter_route
uri: http:
filters:
- name: RequestRateLimiter
args:
rate-limiter: "#{@myRateLimiter}"
key-resolver: "#{@userKeyResolver}"
該過濾器有一個 status 和一個 url參數。status是300類重定向HTTP代碼,如301。該URL應為有效的URL,這將是 Location header的值。
application.yml.
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: http:
filters:
- RedirectTo=302, http:
這將發送一個302狀態碼和一個Location:http://acme.org header來執行重定向。
5.10 RemoveNonProxyHeaders GatewayFilter FactoryRemoveNonProxyHeaders GatewayFilter Factory 從轉發請求中刪除headers。刪除的默認頭列表來自 IETF.
The default removed headers are:
5.11 RemoveRequestHeader GatewayFilter Factory有一個name參數. 這是要刪除的header的名稱。
application.yml.
spring:
cloud:
gateway:
routes:
- id: removerequestheader_route
uri: http:
filters:
- RemoveRequestHeader=X-Request-Foo
這將在X-Request-Foo header被發送到下遊之前刪除它。
5.12 RemoveResponseHeader GatewayFilter Factory有一個name參數. 這是要刪除的header的名稱。
application.yml.
spring:
cloud:
gateway:
routes:
- id: removeresponseheader_route
uri: http:
filters:
- RemoveResponseHeader=X-Response-Foo
這將在返回到網關client之前從響應中刪除x-response-foo頭。
5.13 RewritePath GatewayFilter Factory包含一個 regexp正則表達式參數和一個 replacement 參數. 通過使用Java正則表達式靈活地重寫請求路徑。
application.yml.
spring:
cloud:
gateway:
routes:
- id: rewritepath_route
uri: http:
predicates:
- Path=/foo
對於請求路徑/foo/bar,將在發出下遊請求之前將路徑設置為/bar。注意,由於YAML規範,請使用 $\替換 $。
5.14 RewriteResponseHeader GatewayFilter Factory包含 name, regexp和 replacement 參數.。通過使用Java正則表達式靈活地重寫響應頭的值。
application.yml.
spring:
cloud:
gateway:
routes:
- id: rewriteresponseheader_route
uri: http:
filters:
- RewriteResponseHeader=X-Response-Foo, , password=[^&]+, password=
對於一個/42?user=ford&password=omg!what&flag=true的header值,在做下遊請求時將被設置為/42?user=ford&password=*&flag=true,由於YAML規範,請使用 $\替換 $。
5.15 SaveSession GatewayFilter FactorySaveSession GatewayFilter Factory將調用轉發到下遊之前強制執行WebSession::save 操作。這在使用 Spring Session 之類時特別有用,需要確保會話狀態在進行轉發調用之前已保存。
application.yml.
spring:
cloud:
gateway:
routes:
- id: save_session
uri: http:
predicates:
- Path=/foo
如果你希望要將[Spring Security](https://projects.spring.io/Spring Security/)與Spring Session集成,並確保安全詳細信息已轉發到遠程的進程,這一點至關重要。
5.16 SecureHeaders GatewayFilter FactorySecureHeaders GatewayFilter Factory 將許多headers添加到reccomedation處的響應中,從this blog post.
添加以下標題(使用默認值分配):
X-Xss-Protection:1; mode=block
Strict-Transport-Security:max-age=631138519
X-Frame-Options:DENY
X-Content-Type-Options:nosniff
Referrer-Policy:no-referrer
Content-Security-Policy:default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'
X-Download-Options:noopen
X-Permitted-Cross-Domain-Policies:none
要更改默認值,請在spring.cloud.gateway.filter.secure-headers 命名空間中設置相應的屬性:
Property to change:
5.17 SetPath GatewayFilter FactorySetPath GatewayFilter Factory 採用 template路徑參數。它提供了一種通過允許路徑的模板化segments來操作請求路徑的簡單方法。使用Spring Framework中的URI模板,允許多個匹配segments。
application.yml.
spring:
cloud:
gateway:
routes:
- id: setpath_route
uri: http:
predicates:
- Path=/foo/{segment}
filters:
- SetPath=/{segment}
對於一個 /foo/bar請求,在做下遊請求前,路徑將被設置為/bar
5.18 SetResponseHeader GatewayFilter FactorySetResponseHeader GatewayFilter Factory 包括 name 和 value 參數.
application.yml.
spring:
cloud:
gateway:
routes:
- id: setresponseheader_route
uri: http:
filters:
- SetResponseHeader=X-Response-Foo, Bar
此GatewayFilter使用給定的名稱替換所有header,而不是添加。因此,如果下遊伺服器響應為X-Response-Foo:1234,則會將其替換為X-Response-Foo:Bar,這是網關客戶端將接收的內容。
5.19 SetStatus GatewayFilter FactorySetStatus GatewayFilter Factory 包括唯一的 status參數.必須是一個可用的Spring HttpStatus。它可以是整數值404或字符串枚舉NOT_FOUND。
application.yml.
spring:
cloud:
gateway:
routes:
- id: setstatusstring_route
uri: http:
filters:
- SetStatus=BAD_REQUEST
- id: setstatusint_route
uri: http:
filters:
- SetStatus=401
在這個例子中,HTTP返回碼將設置為401.
5.20 StripPrefix GatewayFilter FactoryStripPrefix GatewayFilter Factory 包括一個parts參數。 parts參數指示在將請求發送到下遊之前,要從請求中去除的路徑中的節數。
application.yml.
spring:
cloud:
gateway:
routes:
- id: nameRoot
uri: http:
predicates:
- Path=/name
當通過網關發出/name/bar/foo請求時,向nameservice發出的請求將是http://nameservice/foo。
5.21 Retry GatewayFilter FactoryRetry GatewayFilter Factory包括 retries, statuses, methods和 series 參數.
retries: 應嘗試的重試次數
statuses: 應該重試的HTTP狀態代碼,用org.springframework.http.HttpStatus標識
methods: 應該重試的HTTP方法,用 org.springframework.http.HttpMethod標識
series: 要重試的一系列狀態碼,用 org.springframework.http.HttpStatus.Series標識
application.yml.
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
注意
retry filter 不支持body請求的重試,如通過body的POST 或 PUT請求
注意
在使用帶有前綴為 forward: 的retry filter時,應仔細編寫目標端點,以便在出現錯誤時不會執行任何可能導致將響應發送到客戶端並提交的操作。例如,如果目標端點是帶註解的controller,則目標controller方法不應返回帶有錯誤狀態代碼的ResponseEntity。相反,它應該拋出一個Exception,或者發出一個錯誤信號,例如通過Mono.error(ex) 返回值,重試過濾器可以配置為通過重試來處理。
當請求大小大於允許的限制時,RequestSize GatewayFilter Factory可以限制請求不到達下遊服務。過濾器以RequestSize作為參數,這是定義請求的允許大小限制(以字節為單位)。
application.yml.
spring:
cloud:
gateway:
routes:
- id: request_size_route
uri: http:
predicates:
- Path=/upload
filters:
- name: RequestSize
args:
maxSize: 5000000
當請求因大小而被拒絕時, RequestSize GatewayFilter Factory 將響應狀態設置為413 Payload Too Large,並帶有額外的header errorMessage 。下面是一個 errorMessage的例子。
errorMessage : Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB
注意
如果未在路由定義中作為filter參數提供,則默認請求大小將設置為5 MB。
這個過濾器被定義為beta版本,將來API可能會改變。
此過濾器可用於在請求主體被網關發送到下遊之前對其進行修改。
注意
只能使用Java DSL配置此過濾器
@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;
}
}
這個過濾器被定義為beta版本,將來API可能會改變。
此過濾器可用於在將響應正文發送回客戶端之前對其進行修改。
注意
只能使用Java DSL配置此過濾器
@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();
}
GlobalFilter接口與GatewayFilter具有相同的籤名。是有條件地應用於所有路由的特殊過濾器。(此接口和用法可能在將來的裡程碑版本中發生更改)。
6.1 全局Filter和GatewayFilter組合排序當請求進入(並與路由匹配)時,篩選Web Handler 會將GlobalFilter的所有實例和所有的GatewayFilter路由特定實例添加到 filter chain。filter組合的排序由org.springframework.core.Ordered接口決定,可以通過實現getOrde()方法或使用@Order注釋來設置。
由於Spring Cloud Gateway將用於執行過濾器邏輯區分為「前置」和「後置」階段,具有最高優先級的過濾器將是「前置」階段的第一個,而「後置」階段的最後一個。
ExampleConfiguration.java.
@Bean
@Order(-1)
public GlobalFilter a() {
return (exchange, chain) -> {
log.info("first pre filter");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("third post filter");
}));
};
}
@Bean
@Order(0)
public GlobalFilter b() {
return (exchange, chain) -> {
log.info("second pre filter");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("second post filter");
}));
};
}
@Bean
@Order(1)
public GlobalFilter c() {
return (exchange, chain) -> {
log.info("third pre filter");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("first post filter");
}));
};
}
ForwardRoutingFilter在exchange屬性ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR中查找URI。如果URL有一個forwardscheme (如 forward:///localendpoint),它將使用Spring DispatcherHandler 來處理請求。請求URL的路徑部分將被轉發URL中的路徑覆蓋。未修改的原始URL將附加到 ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR屬性中的列表中。
6.3 LoadBalancerClient FilterLoadBalancerClientFilter在exchange屬性ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR中查找URI。如果URL有一個lbscheme (如 lb://myservice),它將使用Spring Cloud LoadBalancerClient 將名稱(在前一個示例中為myservice)解析為實際主機和埠,並替換URI。未修改的原始URL將附加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR屬性中的列表中。過濾器還將查看ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR屬性,查看它是否等於lb,然後應用相同的規則。
application.yml.
spring:
cloud:
gateway:
routes:
- id: myRoute
uri: lb:
predicates:
- Path=/service/
注意
默認情況下,如果一個服務實例在LoadBalancer 中沒有發現,則返回503。可以通過設置spring.cloud.gateway.loadbalancer.use404=true來讓網管返回404.
從LoadBalancer返回的ServiceInstance的isSecure 值將覆蓋在對網關發出的請求中指定的scheme。例如,如果請求通過HTTPS進入網關,但ServiceInstance表示它不安全,則下遊請求將通過HTTP協議。相反的情況也適用。但是,如果在網關配置中為路由指定了GATEWAY_SCHEME_PREFIX_ATTR,則前綴將被刪除,並且路由URL生成的scheme將覆蓋ServiceInstance配置。
6.4 Netty Routing Filter如果位於 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR屬性中的URL具有http 或https 模式,則會運行Netty Routing Filter。它使用Netty HttpClient 發出下遊代理請求。響應放在 ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR exchange屬性中,以便在以後的過濾器中使用。(有一個實驗階段不需要Netty的相同的功能的Filter,WebClientHttpRoutingFilter)
6.5 Netty Write Response Filter如果ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR exchange屬性中存在 Netty HttpClientResponse,則運行 NettyWriteResponseFilter 。它在其他所有過濾器完成後將代理響應寫回網關客戶端響應之後運行。(有一個不需要netty的實驗性的WebClientWriteResponseFilter執行相同的功能)
6.6 RouteToRequestUrl Filter如果ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR exchange屬性中存在Route對象,RouteToRequestUrlFilter將運行。它基於請求URI創建一個新的URI,使用Route對象的uri屬性進行更新。新的URI被放置在ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR exchange屬性中。
如果該URI有一個前綴scheme,例如lb:ws://serviceid,則會從該URI中剝離該 lb scheme,並將其放置在ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR中,以便稍後在過濾器鏈中使用。
6.7 Websocket Routing Filter如果ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTRexchange屬性中有 ws 、 wssscheme,則Websocket Routing Filter將被運行。它使用Spring Web Socket基礎模塊將Websocket轉發到下遊。
URI前綴為lb的Websockets可以被負載均衡,如 lb:ws://serviceid.
注意
如果使用 SockJS 作為普通HTTP的fallback,則應配置普通HTTP路由以及WebSocket路由。
application.yml.
spring:
cloud:
gateway:
routes:
# SockJS route
- id: websocket_sockjs_route
uri: http:
predicates:
- Path=/websocket/info
要啟用網關指標,請將spring-boot-starter-actuator添加為項目依賴項。然後,默認情況下,只要屬性spring.cloud.gateway.metrics.enabled未設置為false,網關指標過濾器就會運行。此過濾器添加名為「gateway.requests」的計時器指標,並帶有以下標記:
這些指標可以從/actuator/metrics/gateway.requests中獲取,可以很容易地與Prometheus集成以創建Grafana dashboard.
注意
要將pometheus啟用,需要添加 micrometer-registry-prometheus為項目依賴。
網關路由ServerWebExchange之後,它將通過向Exchange屬性添加gatewayAlreadyRouted,將該exchange標記為「routed」。一旦一個請求被標記為routed,其他路由過濾器將不會再次路由該請求,將跳過該過濾器。有一些方便的方法可以用來將exchange標記為routed,或者檢查exchange是否已經routed。
7. TLS / SSL網關可以通過常規的 Spring server configuration 來偵聽HTTPS上的請求。例子:
application.yml.
server:
ssl:
enabled: true
key-alias: scg
key-store-password: scg1234
key-store: classpath:scg-keystore.p12
key-store-type: PKCS12
網關路由可以路由到HTTP和HTTPS後端。如果路由到HTTPS後端,則可以將網關配置為信任所有具有證書的下遊服務:
application.yml.
spring:
cloud:
gateway:
httpclient:
ssl:
useInsecureTrustManager: true
不建議在生產環境使用不安全的信任管理器。對於生產部署,可以使用一組已知證書配置網關,這些證書可以通過以下方式進行配置:
application.yml.
spring:
cloud:
gateway:
httpclient:
ssl:
trustedX509Certificates:
- cert1.pem
- cert2.pem
如果Spring Cloud Gateway未配置受信任證書,則使用默認信任庫(可以使用系統屬性javax.net.ssl.trustStore覆蓋)。
7.1 TLS 握手網關維護一個用於路由到後端的client池。當通過HTTPS通信時,客戶端啟動一個TLS握手,其中可能會有很多超時。這些超時可以這樣配置(顯示默認值):
application.yml.
spring:
cloud:
gateway:
httpclient:
ssl:
handshake-timeout-millis: 10000
close-notify-flush-timeout-millis: 3000
close-notify-read-timeout-millis: 0
Spring Cloud Gateway的配置由RouteDefinitionLocator的集合驅動。
RouteDefinitionLocator.java.
public interface RouteDefinitionLocator {
Flux<RouteDefinition> getRouteDefinitions();
}
默認情況下,PropertiesRouteDefinitionLocator使用Spring Boot的@ConfigurationProperties機制加載屬性。
以下兩個示例是等效的:
application.yml.
spring:
cloud:
gateway:
routes:
- id: setstatus_route
uri: http:
filters:
- name: SetStatus
args:
status: 401
- id: setstatusshortcut_route
uri: http:
filters:
- SetStatus=401
對於網關的大部分用法,配置文件方式是夠用的,但一些生產用例更建議從外部源(如資料庫)加載配置。未來的裡程碑版本將有基於Spring Data Repositories (如Redis、MongoDB和Cassandra)的RouteDefinitionLocator實現。
8.1 Fluent Java Routes API為了可以更簡單在Java中配置,在RouteLocatorBuilder bean中定義了一個fluent API。
GatewaySampleApplication.java.
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder, ThrottleGatewayFilterFactory throttle) {
return builder.routes()
.route(r -> r.host(".abc.org").and().path("/image/png")
.filters(f ->
f.addResponseHeader("X-TestHeader", "foobar"))
.uri("http://httpbin.org:80")
)
.route(r -> r.path("/image/webp")
.filters(f ->
f.addResponseHeader("X-AnotherHeader", "baz"))
.uri("http://httpbin.org:80")
)
.route(r -> r.order(-1)
.host(".throttle.org").and().path("/get")
.filters(f -> f.filter(throttle.apply(1,
1,
10,
TimeUnit.SECONDS)))
.uri("http://httpbin.org:80")
)
.build();
}
這種樣式還允許使用更多的自定義斷言。由RouteDefinitionLocator beans定義的斷言使用邏輯 and組合。通過使用fluent Java API,可以在 Predicate類上使用 and()、or() 、 negate()運算符。
8.2 DiscoveryClient Route Definition Locator可以將網關配置為基於使用兼容DiscoveryClient註冊中心註冊的服務來創建路由。
要啟用此功能,請設置spring.cloud.gateway.discovery.locator.enabled=true,並確保DiscoveryClient實現位於classpath上並已啟用(如netflix eureka、consul或zookeeper)。
8.2.1 Configuring Predicates and Filters For DiscoveryClient Routes默認情況下,網關為通過DiscoveryClient創建的路由定義單個斷言和過濾器。
默認斷言是使用/serviceId/定義的path斷言,其中serviceId是DiscoveryClient中服務的ID。
默認過濾器是使用正則表達式 /serviceId/(?<remaining>.)和替換的/${remaining}進行重寫。這只是在請求被發送到下遊之前從路徑中截取掉 service id 。
可以通過設置spring.cloud.gateway.discovery.locator.predicates[x] and spring.cloud.gateway.discovery.locator.filters[y]來實現自定義DiscoveryClient路由使用的斷言and/or過濾器。當你這樣做時,如果你想要保留這個功能,你需要確保包括上面的默認斷言和過濾器。下面是這樣一個例子。
application.properties.
spring.cloud.gateway.discovery.locator.predicates[0].name: Path
spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]: "'/'+serviceId+'/'"
spring.cloud.gateway.discovery.locator.predicates[1].name: Host
spring.cloud.gateway.discovery.locator.predicates[1].args[pattern]: "'.foo.com'"
spring.cloud.gateway.discovery.locator.filters[0].name: Hystrix
spring.cloud.gateway.discovery.locator.filters[0].args[name]: serviceId
spring.cloud.gateway.discovery.locator.filters[1].name: RewritePath
spring.cloud.gateway.discovery.locator.filters[1].args[regexp]: "'/' + serviceId + '/(?<remaining>.)'"
spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'"
設置 -Dreactor.netty.http.server.accessLogEnabled=true 來開啟Reactor Netty access logs,注意必須是Java System Property而不是Spring Boot property。
logging 模塊也可以通過配置單獨輸出一個access log文件,下面是logback的配置例子:
logback.xml.
<appender name="accessLog" class="ch.qos.logback.core.FileAppender">
<file>access_log.log</file>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<appender name="async" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="accessLog" />
</appender>
<logger name="reactor.netty.http.server.AccessLog" level="INFO" additivity="false">
<appender-ref ref="async"/>
</logger>
我們可以通過配置網關來控制CORS行為,全局CORS配置是 Spring Framework CorsConfiguration模式的URL MAP。
application.yml.
spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/*]':
allowedOrigins: "http://docs.spring.io"
allowedMethods:
- GET
例子中將允許從docs.spring.io發出的所有GET請求進行CORS請求。
11. Actuator API/gateway的actuator端點允許監視Spring Cloud Gateway應用程式並與之交互。要進行遠程訪問,必須在應用程式屬性中暴露HTTP或JMX 埠。
application.properties.
management.endpoint.gateway.enabled=true
management.endpoints.web.exposure.include=gateway
要檢索應用於所有路由的 [global filters],請get請求 /actuator/gateway/globalfilters。返回的結果類似於以下內容:
{
"org.springframework.cloud.gateway.filter.LoadBalancerClientFilter@77856cc5": 10100,
"org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@4f6fd101": 10000,
"org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@32d22650": -1,
"org.springframework.cloud.gateway.filter.ForwardRoutingFilter@106459d9": 2147483647,
"org.springframework.cloud.gateway.filter.NettyRoutingFilter@1fbd5e0": 2147483647,
"org.springframework.cloud.gateway.filter.ForwardPathFilter@33a71d23": 0,
"org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@135064ea": 2147483637,
"org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@23c05889": 2147483646
}
返回結果包含已就緒的global filters的詳細信息(如 org.springframework.cloud.gateway.filter.LoadBalancerClientFilter@77856cc5)。對於每個global filters,返回結果字符串對應過濾器鏈中的相應順序。
11.1.2 Route Filters要檢索應用於路由的 [GatewayFilter factories] ,請get請求/actuator/gateway/routefilters。返回結果類似於以下內容:
{
"[AddRequestHeaderGatewayFilterFactory@570ed9c configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null,
"[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]": null,
"[SaveSessionGatewayFilterFactory@4449b273 configClass = Object]": null
}
返回結果包含應用於所有路由的GatewayFilter的詳細信息。顯示每個工廠提供字符串格式的相應對象(例如, [SecureHeadersGatewayFilterFactory@fceab5d configClass = Object])。請注意,null值是由於endpoint controller實現不完整造成的,因為它嘗試在filter chain中設置對象的順序,這不適用於GatewayFilter工廠對象。
11.2 Refreshing the route cache如果要清理路由的緩存,請POST請求/actuator/gateway/refresh。該請求將返回一個沒有body的200返回碼。
11.3 Retrieving the routes defined in the gateway要檢索網關中定義的路由,發送GET請求/actuator/gateway/routes,返回結果如下所示:
[{
"route_id": "first_route",
"route_object": {
"predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@1e9d7e7d",
"filters": [
"OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.PreserveHostHeaderGatewayFilterFactory$$Lambda$436/674480275@6631ef72, order=0}"
]
},
"order": 0
},
{
"route_id": "second_route",
"route_object": {
"predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@cd8d298",
"filters": []
},
"order": 0
}]
返回結果中包含網關中所有定義的路由信息,下面表格中描述了返回結果信息:
11.4 Retrieving information about a particular route要獲取單個路由的信息,發送GET請求 /actuator/gateway/routes/{id} (如: /actuator/gateway/routes/first_route),返回結果如下所示:
{
"id": "first_route",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"/first"}
}],
"filters": [],
"uri": "http://www.uri-destination.org",
"order": 0
}]
下面表格中描述了返回結果信息:
11.5 Creating and deleting a particular route要創建一個路由,發送POST請求 /gateway/routes/{id_route_to_create},參數為JSON結構,具體參數數據結構參考上面章節。
要刪除一個路由,發送 DELETE請求 /gateway/routes/{id_route_to_delete}。
11.6 Recap: list of all endpoints下表總結了Spring Cloud Gateway actuator endpoints。注意,每個endpoint都是/actuator/gateway作為基本路徑。
12. Developer GuideTODO: overview of writing custom integrations
12.1 Writing Custom Route Predicate FactoriesTODO: document writing Custom Route Predicate Factories
12.2 Writing Custom GatewayFilter Factories如果要自定義一個GatewayFilter,需要實現GatewayFilterFactory。下面是一個你需要集成的抽象類 AbstractGatewayFilterFactory。
PreGatewayFilterFactory.java.
public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> {
public PreGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
return chain.filter(exchange.mutate().request(request).build());
};
}
public static class Config {
}
}
PostGatewayFilterFactory.java.
public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> {
public PostGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
ServerHttpResponse response = exchange.getResponse();
}));
};
}
public static class Config {
}
}
TODO: document writing Custom Global Filters
12.4 Writing Custom Route Locators and WritersTODO: document writing Custom Route Locators and Writers