👏大家好,欢迎来到👏阿提说说👏博客
🌞“纸上得来终觉浅,绝知此事要躬行。”(南宋)陆游
🌲目前相关的教程虽然有很多,但总觉得被各位大佬压缩,看到的只是一部分知识,并不全面,因此作者根据Spring Cloud Gateway 官方参考指南写下了这篇中文版文字教程,并且录制了一些视频教程,希望更有助于您理解。
🍀Spring Cloud Gateway 版本为 3.1.3
Spring Cloud Gateway参考指南
该项目提供了一个基于Spring生态的API网关。Spring Cloud Gateway。Spring Cloud Gateway旨在提供一个种简单有效的方式去路由API,并给API提供相应关注点:如:security、monitoring/metrics和resiliency。
1. 如何引入Spring Cloud Gateway
要在项目中引入Spring Cloud Gateway,您可以这样做:
- 引入Spring Cloud 统一版本依赖管理,通过引入该配置,无需指定Spring Cloud相关组件版本
<dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>
- 引入Spring Cloud Gateway配置
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>
🚩 如果引入了Spring Cloud Gateway,又不想开启,可以设置
spring.cloud.gateway.enabled=false
❗️ Spring Cloud Gateway建立在Spring Boot 2.x,Spring WebFlux 和 Project Reactor之上,当您使用Spring Cloud Gateway时,以前的同步库(Spring Data 、Spring Security等)并不适用。如果您不熟悉这些项目,建议您在使用Spring Cloud Gateway之前,先阅读他们的文档,熟悉一些概念。
❗️ Spring Cloud Gateway 使用Spring Boot 和Spring Webflux 提供的Netty环境运行,因此在传统的Servlet容器中不会生效。
2. 相关术语
- Route: 路由,网关基础模块。它由ID、目标URI、断言集合和过滤器集合组成。如果断言为真,则匹配到该路由。
- Predicate:这是一个Java8 的函数断言。输入类型是Spring Framework 的 ServerWebExchange。
- Filter: 使用指定工厂构建的GatewayFilter的实例。在这里,您能够修改request请求和response返回在发送到下游服务之前或者之后。
3. 如何工作
下图是SPring Cloud Gateway的工作示意图:
客户端向Spring Cloud Gateway请求。如果网关处理程序(Gateway Handler Mapping)确定请求与路由匹配,那么将其发送到网关的Web处理器(Gateway Web Handler)。该处理程序通过过滤器链来处理请求。过滤器链被虚线分割的原因是,过滤器可以在请求发送前后运行逻辑,先执行所有的“pre”过滤器逻辑,后执行“post”过滤器逻辑。
✅ 在未定义端口的URI中,HTTP默认为80,HTTPS默认为443。
4. 配置路由断言工厂和网关过滤工厂
有两种方法配置谓词和过滤器:简写和完全展开方式。下面的例子大都用的简写。
4.1 简写
简写配置由过滤器名称,后跟等号,后跟逗号分割的参数值。
application.yml
spring:cloud:gateway:routes:-id: after_route
uri: https://example.org
predicates:- Cookie=mycookie,mycookievalue
4.2 完全展开
完全展开方式具有标准的name/value 对。一般带有name 和 args 两个key。args用来配置断言或过滤器的键值对映射。
application.yml
spring:cloud:gateway:routes:-id: after_route
uri: https://example.org
predicates:-name: Cookie
args:name: mycookie
regexp: mycookievalue
5. 路由断言工厂
Spring Cloud Gateway 路由匹配作为Spring WebFlux
HandlerMapping
基础设施的一部分。Spring Cloud Gateway内置了很多路由断言工厂。用于匹配HTTP请求的不同属性。
5.1 After Route Predicate Factory
接收一个java
ZonedDateTime
的时间参数,表示这个时间之后的请求才能正确匹配路由。
Example 1.application.yml
spring:cloud:gateway:routes:-id: after_route
uri: https://example.org
predicates:- After=2017-01-20T17:42:47.789-07:00[America/Denver]
这个路由匹配 Jan 20, 2017 17:42 Mountain Time (Denver)之后的请求。
5.2 Before Route Predicate Factory
接收一个Java ZonedDateTime类的时间参数,表示这个时间之前的请求才能正确匹配路由。
Example 2. application.yml
spring:cloud:gateway:routes:-id: before_route
uri: https://example.org
predicates:- Before=2017-01-20T17:42:47.789-07:00[America/Denver]
5.3 Between Route Predicate Factory
接收两个Java ZonedDateTime类的时间参数,表示在第一个时间之后,第二个时间之前的请求才能正确匹配路由。
Example 3. application.yml
spring:cloud:gateway:routes:-id: between_route
uri: https://example.org
predicates:- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
5.4 Cookie Route Predicate Factory
接收两个参数,分别为name 和 regexp(Java正则表达式),表示cookie中携带的name值满足正则表达式regexp,则被路由。
Example 4. application.yml
spring:cloud:gateway:routes:-id: cookie_route
uri: https://example.org
predicates:- Cookie=chocolate, ch.p
5.5 Header Route Predicate Factory
接收两个参数,header 和 regexp(Java正则表达式),表示header中携带的name值满足正则表达式regexp,则被路由
Example 5. application.yml
spring:cloud:gateway:routes:-id: header_route
uri: https://example.org
predicates:- Header=X-Request-Id, \d+
5.6 Host Route Predicate Factory
接收一个主机名称的集合参数,用逗号分割,表示该断言与主机头匹配则被路由。
Example 6. application.yml
spring:cloud:gateway:routes:-id: host_route
uri: https://example.org
predicates:- Host=**.somehost.org,**.anotherhost.org
支持URI模板变量(如{sub}.myhost.org)。
当Host 头的值为
www.somehost.org 或 beta.somehost.org 或 www.anotherhost.org
都能匹配该路由。
Predicate 会提取URI模板变量作为map集合,并放置在
ServerWebExchange.getAttributes()
中,key定义为
ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE
,这些值能在
GatewayFilter 工厂
中使用。
5.7 Mehtod Route Predicate Factory
接收一个或多个http请求参数,如果请求方法匹配,则被路由。
Example 7. application.yml
spring:cloud:gateway:routes:-id: method_route
uri: https://example.org
predicates:- Method=GET,POST
5.8 Path Route Predicate Factory
接收两个参数,分别是Spring PathMatcher patterns 列表 和 一个matchTrailingSlash的可选标志(默认为true)。
Example 8. application.yml
spring:cloud:gateway:routes:-id: path_route
uri: https://example.org
predicates:- Path=/red/{segment},/blue/{segment}
如果请求地址是
/red/1 或 /red/1/ 或 /red/blue 或 /blue/green
,那么路由将会被匹配。
如果
matchTrailingSlash
设置为
false
,那么
/red/1/
不会被匹配。
Predicate 会提取URI模板变量作为map集合,并放置在
ServerWebExchange.getAttributes()
中,key定义为
ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE
,这些值能在
GatewayFilter 工厂
中使用。
可以使用一个实用方法(调用get)来简化对这些变量的访问。下面的例子展示了如何使用get方法:
Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);
String segment = uriVariables.get("segment");
5.9 Query Route Predicate Factory
接收两个参数,分别是一个必须的param和一个可选的regexp。
Example 9. application.yml
spring:cloud:gateway:routes:-id: query_route
uri: https://example.org
predicates:- Query=green
application.yml
spring:cloud:gateway:routes:-id: query_route
uri: https://example.org
predicates:- Query=red, gree.
如果请求中包含一个red查询参数,且该参数的值匹配gree.正则表达式,则上述路由匹配。所以green和greet是匹配的。
5.10 RemoteAddr Route Predicate Factory
接收一个sources列表(最小1个),CIDR表示法(IPv4或IPv6)字符串,例如192.168.0.1/16(其中192.168.0.1是一个IP地址,16是一个子网掩码)。
Example 10. application.yml
spring:cloud:gateway:routes:-id: remoteaddr_route
uri: https://example.org
predicates:- RemoteAddr=192.168.1.1/24
如果请求的远程地址是
192.168.1.10
,则此路由被匹配。
5.10.1 修改远程地址的解析方式
默认情况下,RemoteAddr 路由谓词工厂使用来自传入请求的远程地址。如果 Spring Cloud Gateway 位于代理层后面,这可能与实际客户端 IP 地址不匹配。
您可以通过设置自定义
RemoteAddressResolver
来自定义解析远程地址的方式。 Spring Cloud Gateway 附带一个基于 X-Forwarded-For 标头
XForwardedRemoteAddressResolver
的非默认远程地址解析器
XForwardedRemoteAddressResolver
有两个静态构造方法,它们采用不同的安全方法
XForwardedRemoteAddressResolver::trustAll
返回一个 RemoteAddressResolver,它总是采用在 X-Forwarded-For 标头中找到的第一个 IP 地址。这种方法容易受到欺骗,因为恶意客户端可以为 X-Forwarded-For 设置初始值,解析器会接受该值。XForwardedRemoteAddressResolver::maxTrustedIndex
采用与 Spring Cloud Gateway 前运行的受信任基础设施数量相关的索引。例如,如果 Spring Cloud Gateway 只能通过 HAProxy 访问,则应使用值 1。如果在访问 Spring Cloud Gateway 之前需要两跳可信基础架构,则应使用值 2。 考虑以下标头值:
X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3
以下 maxTrustedIndex 值产生以下远程地址:
maxTrustedIndex
result[
Integer.MIN_VALUE
,0](invalid,
IllegalArgumentException
during initialization)10.0.0.320.0.0.230.0.0.1[4,
Integer.MAX_VALUE
]0.0.0.1
以下示例显示了如何使用 Java 实现相同的配置:
Example 11. 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"))
5.11 Weight Route Predicate Factory
接收两个参数:分别是group 和 weight(int类型)。权重是按组计算的。
Example 12. application.yml
spring:cloud:gateway:routes:-id: weight_high
uri: https://weighthigh.org
predicates:- Weight=group1,8-id: weight_low
uri: https://weightlow.org
predicates:- Weight=group1,2
将有80%的流量被路由到
weighthigh.org
,20%的流量被路由到
weightlow.org
。
5.12 XForwarded Remote Addr Route Predicate Factory
接收一个sources列表(最小大小为 1),这些源是 CIDR 表示法(IPv4 或 IPv6)字符串,例如
192.168.0.1/16
(其中 192.168.0.1 是 IP 地址,16 是子网掩码)
此路由断言允许基于
X-Forwarded-For
HTTP 标头过滤请求。
这可以与反向代理一起使用,例如负载平衡器或 Web 应用程序防火墙,其中仅当请求来自这些反向代理使用的受信任的 IP 地址列表时才允许请求。
以下示例配置 XForwardedRemoteAddr 路由谓词:
Example 13. application.yml
spring:cloud:gateway:routes:-id: xforwarded_remoteaddr_route
uri: https://example.org
predicates:- XForwardedRemoteAddr=192.168.1.1/24
如果
X-Forwarded-For
标头包含例如
192.168.1.10
,则此路由匹配。
6. 网关过滤器工厂(GatewayFilter)
路由过滤器允许修改传入的HTTP请求和传出的HTTP响应。Spring Cloud Gateway包括了许多内置的GatewayFilter Factories。
关于过滤器的更多示例,查看单元测试。
6.1 AddRequestHeader GatewayFilter Factory
接收一个
name
和
value
参数,并将信息添加到下游的请求头中。
Example 14. application.yml
spring:cloud:gateway:routes:-id: add_request_header_route
uri: https://example.org
filters:- AddRequestHeader=X-Request-red, blue
AddRequestHeader
支持使用URI变量来匹配path 或 host。
Example 15. application.yml
spring:cloud:gateway:routes:-id: add_request_header_route
uri: https://example.org
predicates:- Path=/red/{segment}filters:- AddRequestHeader=X-Request-Red, Blue-{segment}
6.2 AddRequestParameter GatewayFilter Factory
接收一个name 和 value 参数,并添加信息到下游的请求中。
Example 16. application.yml
spring:cloud:gateway:routes:-id: add_request_parameter_route
uri: https://example.org
filters:- AddRequestParameter=red, blue
支持使用URI变量来匹配path 或 host。
Example 17. application.yml
spring:cloud:gateway:routes:-id: add_request_parameter_route
uri: https://example.org
predicates:-Host:{segment}.myhost.org
filters:- AddRequestParameter=foo, bar-{segment}
6.3 AddResponseHeader GatewayFilter Factory
接收一个name 和 value 参数,并将信息添加到下游匹配请求的响应头中。
Example 18. application.yml
spring:cloud:gateway:routes:-id: add_response_header_route
uri: https://example.org
filters:- AddResponseHeader=X-Response-Red, Blue
支持使用URI变量来匹配path 或 host。
Example 19. application.yml
spring:cloud:gateway:routes:-id: add_response_header_route
uri: https://example.org
predicates:-Host:{segment}.myhost.org
filters:- AddResponseHeader=foo, bar-{segment}
6.4 DedupeResponseHeader GatewayFilter Factory
接收一个name参数和一个可选的strategy参数,name 参数根据空格分割。
Example 20. application.yml
spring:cloud:gateway:routes:-id: dedupe_response_header_route
uri: https://example.org
filters:- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
当网关CROS和下游响应头都有Access-Control-Allow-Credentials 和 Access-Control-Allow-Origin时,将删除重复的响应头。
DedupeResponseHeader
过滤器也接收可选的
strategy
参数,可接收的值是RETAIN_FIRST (default), RETAIN_LAST 和 RETAIN_UNIQUE
6.5 CircuitBreaker GatewayFilter Factory(演示)
使用 Spring Cloud CircuitBreaker的API将网关路由包装到断路器中。Spring Cloud CircuitBreaker 支持多种库用于Spring Cloud Gateway。比如Resilience4J。
要启用Spring Cloud CircuitBreaker过滤器,你需要引入
spring-cloud-starter-circuitbreaker-reactor-resilience4j
,如下是配置示例:
Example 21. application.yml
spring:cloud:gateway:routes:-id: circuitbreaker_route
uri: https://example.org
filters:- CircuitBreaker=myCircuitBreaker
要配置 circuit breaker,可以详细查看Resilience4J Documentation
Spring Cloud CircuitBreaker 过滤器也支持接收可选的
fallbackUri
参数。当前,仅
forward:
支持,如果请求失败,请求将会跳转到匹配URI的controller中。
Example 22. application.yml
spring:cloud:gateway:routes:-id: circuitbreaker_route
uri: lb://backing-service:8088predicates:- Path=/consumingServiceEndpoint
filters:-name: CircuitBreaker
args:name: myCircuitBreaker
fallbackUri: forward:/inCaseOfFailureUseThis
- RewritePath=/consumingServiceEndpoint, /backingServiceEndpoint
🚩
RewritePath
表示将
/consumingServiceEndpoint
路径在请求前重写为
/backingServiceEndpoint
下面是Java的实现方式:
Example 23. Application.java
@BeanpublicRouteLocatorroutes(RouteLocatorBuilder builder){return builder.routes().route("circuitbreaker_route", r -> r.path("/consumingServiceEndpoint").filters(f -> f.circuitBreaker(c -> c.name("myCircuitBreaker").fallbackUri("forward:/inCaseOfFailureUseThis")).rewritePath("/consumingServiceEndpoint","/backingServiceEndpoint")).uri("lb://backing-service:8088").build();}
当前请求被熔断时,将被回调到
/inCaseofFailureUseThis
。
✅ 动图演示
gateway: 测试网关
backing-service: 测试后端服务
- 熔断跳转到inCaseOfFailureUseThis
- 重写跳转到backingServiceEndpoint
这里fallbackUri主要使用在网关应用程序内部定义controller或者handler。您也可以重路由到外部应用程序。如下示例:
Example 24. application.yml
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:9994predicates:- Path=/fallback
该示例中,网关没有fallback 端点或处理程序。但是注册了一个
localhost:9994
的应用程序。
在请求被转发到fallback的时候,Spring Cloud CircuitBreaker Gateway filter 也提供
Throwable
异常。它被添加到
ServerWebExchange
的
ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR
中,以便可以在网关应用程序中使用。
对于外部controller/handler场景,可以添加带有异常详情信息的头。您可以在FallbackHeaders GatewayFilter Factory section中找到更多详情。
6.5.1 根据状态码熔断
通过配置的
statusCodes
,当返回配置的状态码时,请求熔断。状态码可以配置整型状态码值或者
HttpStatus
的枚举字符串。
Example 25. application.yml
spring:cloud:gateway:routes:-id: circuitbreaker_route
uri: lb://backing-service:8088predicates:- Path=/consumingServiceEndpoint
filters:-name: CircuitBreaker
args:name: myCircuitBreaker
fallbackUri: forward:/inCaseOfFailureUseThis
statusCodes:-500-"NOT_FOUND"
Java 代码表示
Example 26. Application.java
@BeanpublicRouteLocatorroutes(RouteLocatorBuilder builder){return builder.routes().route("circuitbreaker_route", r -> r.path("/consumingServiceEndpoint").filters(f -> f.circuitBreaker(c -> c.name("myCircuitBreaker").fallbackUri("forward:/inCaseOfFailureUseThis").addStatusCode("INTERNAL_SERVER_ERROR")).rewritePath("/consumingServiceEndpoint","/backingServiceEndpoint")).uri("lb://backing-service:8088").build();}
6.6 FallbackHeaders GatewayFilter Factory
FallbackHeaders
工厂允许您在转发到外部应用程序的
fallbackUri
中添加Spring Cloud CircuitBreaker 详细的异常信息,如下所示:
Example 27. application.yml
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:9994predicates:- Path=/fallback
filters:-name: FallbackHeaders
args:executionExceptionTypeHeaderName: Test-Header
在该例中,在运行circuit breaker 发生异常后,请求将被转发到
http://localhost:9994
的
/fallback
中。异常类型、消息等通过
FallbackHeaders
过滤器添加到请求头中。
通过设置下面列出的参数值,可以在配置中覆盖headers的名称。
- executionExceptionTypeHeaderName (“Execution-Exception-Type”)
- executionExceptionMessageHeaderName (“Execution-Exception-Message”)
- rootCauseExceptionTypeHeaderName (“Root-Cause-Exception-Type”)
- rootCauseExceptionMessageHeaderName (“Root-Cause-Exception-Message”)
更多详情查看Spring Cloud CircuitBreaker Factory section
6.7 MapRequestHeader GatewayFilter Factory(演示)
接收两个参数,分别是fromHeader 和 toHeader。它会创建一个新的header(
toHeader
),并从
fromHeader
中提取值。如果输入的header不存在,该过滤器不会执行。如果新的header已经存在,那么它将被追加新值。如下所示:
Example 28. application.yml
spring:cloud:gateway:routes:-id: map_request_header_route
uri: https://example.org
filters:- MapRequestHeader=Blue, X-Request-Red
该示例会将
X-Request-Red:<values>
头添加到下游请求中,值为传入的HTTP请求
Blue
值。
✅视频演示
MapperRequestHeader GatewayFilter示例演示
6.8 PrefixPath GatewayFilter Factory
接收一个参数
prefix
Example 29. application.yml
spring:cloud:gateway:routes:-id: prefixpath_route
uri: https://example.org
filters:- PrefixPath=/mypath
该示例将在所有匹配请求路径前加上前缀
/mypath
,因此请求
/hello
时,将发送到
/mypath/hello
中。
6.9 PreserveHostHeader GatewayFilter Factory(演示)
该过滤工厂没有接收参数。设置了该Filter后,GatewayFilter将不使用由HTTP客户端确定的host header ,而是发送原始host header。
Example 30. application.yml
spring:cloud:gateway:routes:-id: preserve_host_route
uri: https://example.org
filters:- PreserveHostHeader
✅视频演示
PreserveHostHeader GatewayFilter 示例演示
6.10 RequestRateLimiter GatewayFilter Factory
该过滤器使用
RateLimiter
来实现是否允许继续执行该请求。如果不允许继续执行,返回
HTTP 429 - Too Many Requests
(默认情况下)。
该过滤器可以配置一个可选的
keyResolver
参数和rate limiter参数。
keyResolver
是
KeyResolver
的一个实现类,在配置中,按名称使用SpEL引用bean。#{@myKeyResolver}是引用名为’myKeyResolver’的bean的SpEL表达式。
Example 31. KeyResolver.java
publicinterfaceKeyResolver{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
❗️
RequestRateLimiter
不能使用“shortcut”来配置,如下配置无效:
# INVALID SHORTCUT CONFIGURATION spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2, #{@userkeyresolver}
6.10.1 Redis RateLimiter(演示)
Redis实现基于Stripe。它需要引入
spring-boot-starter-data-redis-reactive
依赖。
使用的算法是Token Bucket Algorithm。
redis-rate-limiter.replenishRate
配置是在不丢弃任何请求的情况下,你允许用户每秒执行多少请求。这是令牌桶的填充速率。
redis-rate-limiter.burstCapacity
配置是允许用户在一秒内执行的最大请求数。这是令牌桶可以保存的令牌数。将此值设置为0将阻止所有请求。
redis-rate-limiter.requestedTokens
配置一个请求所需要的令牌数。每个请求从令牌桶提取的令牌数,默认为1。
通过在
replenishRate
和
burstCapacity
中设置相同的值来实现稳定的速率。可通过设置
burstCapacity
高于
replenishRate
来允许临时突发流量。在这种情况下,限流器需要在两次突发之间留出一段时间(根据
replenishRate
),因为连续两次突发将导致请求丢失 (HTTP 429 - Too Many Requests)。如下列表配置了一个
redis-rate-limiter
:
比如:
replenishRate=1
、
requestedTokens=60
和
burstCapacity=60
将限制为
1 request/min
。
Example 33. application.yml
spring:cloud:gateway:routes:-id: requestratelimiter_route
uri: https://example.org
filters:-name: RequestRateLimiter
args:redis-rate-limiter.replenishRate:10redis-rate-limiter.burstCapacity:20redis-rate-limiter.requestedTokens:1
配置一个KeyResolver
**Example 34. Config.java
@BeanKeyResolveruserKeyResolver(){return exchange ->Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));}
这定义了每个用户10个请求的限制。允许20个突发,但下一秒只有10个请求可用。
KeyResolver
是一个简单的获取user请求参数的工具(注意:不建议用于生产)。
限流器也可以定义为
RateLimiter
接口的实现 bean。在配置中,按名称使用SpEL引用bean。
#{@myRateLimiter}
是引用名为
myRateLimiter
的bean的SpEL表达式。
Example 35. application.yml
spring:cloud:gateway:routes:-id: requestratelimiter_route
uri: https://example.org
filters:-name: RequestRateLimiter
args:rate-limiter:"#{@myRateLimiter}"key-resolver:"#{@userKeyResolver}"
✅视频演示
RequestRateLimiter GatewayFilter 示例演示
6.11 RedirectTo GatewayFilter Factory
接收两个参数:
status
和
url
。
status
是300类重定向HTTP码,如301。该
url
应该是一个有效的URL,值是
Location
header的值。
对于相对路径,应该使用
uri: no://op
作为路由定义。
Example 36. application.yml
spring:cloud:gateway:routes:-id: prefixpath_route
uri: https://example.org
filters:- RedirectTo=302, https://acme.org
该例将发送一个302重定向状态码到
Location:https://acme.org
。
6.12 RemoveRequestHeader GatewayFilter Factory
接收一个
name
参数,该值是将要被删除header的name。
Example 37. application.yml
spring:cloud:gateway:routes:-id: removerequestheader_route
uri: https://example.org
filters:- RemoveRequestHeader=X-Request-Foo
该例表示将从header中删除
X-Request-Foo
。
6.13 RemoveResponseHeader GatewayFilter Factory
接收一个参数
name
,name将在响应返回之前被删除。
Example 38. application.yml
spring:cloud:gateway:routes:-id: removeresponseheader_route
uri: https://example.org
filters:- RemoveResponseHeader=X-Response-Foo
该例表示响应在返回网关之前将从header中删除
X-Response-Foo
。
可以使用
spring.cloud.gateway.default-filters
配置默认过滤,该默认过滤对所有路由有效。
6.14 RemoveRequestParameter GatewayFilter Factory
接收一个
name
参数,它是要被删除请求参数的name值。
Example 39. application.yml
spring:cloud:gateway:routes:-id: removerequestparameter_route
uri: https://example.org
filters:- RemoveRequestParameter=red
该例表示在将请求发送到下游之前,删除
red
参数。
6.15 RequestHeaderSize GatewayFilter Factory
接收两个参数,
maxSize
和
errorHeaderName
。
maxSize
表示请求头的最大数据带下(包括key和value)。
errorHeaderName
用于设置响应头的名称,包含错误信息,默认名称为
errorMessage
。
Example 40. application.yml
spring:cloud:gateway:routes:-id: requestheadersize_route
uri: https://example.org
filters:- RequestHeaderSize=1000B
该示例表示如果请求超过了1000Bytes,将发送一个431的状态码。
6.16 RewritePath GatewayFilter Factory
接收一个
regexp
和
replacement
参数。使用了Java正则表达式来重写请求地址。
Example 41. application.yml
spring:cloud:gateway:routes:-id: rewritepath_route
uri: https://example.org
predicates:- Path=/red/**filters:- RewritePath=/red/?(?<segment>.*), /$\{segment}
对于
/red/blue
请求路径,将在发送到下游之前替换为
/blue
。因为YAML规范,要把
$
替换为
$\
。
6.17 RewriteLocationResponseHeader GatewayFilter Factory
该过滤器修改
Location
响应头的值,经常用于去掉一些敏感信息。接收参数分别是:
stripVersionMode, locationHeaderName, hostValue, protocolsRegex
。
Example 42. application.yml
spring:cloud:gateway:routes:-id: rewritelocationresponseheader_route
uri: http://example.org
filters:- RewriteLocationResponseHeader=AS_IN_REQUEST, Location,,
示例表示,一个POST请求
api.example.com/some/object/name
,
Location
响应头的值是
object-service.prod.example.net/v2/some/object/id
将被重写为
api.example.com/some/object/id
。
stripVersionMode
参数有以下值:
NEVER_STRIP
,
AS_IN_REQUEST
(默认), 和
ALWAYS_STRIP
。
- NEVER_STRIP:原始的请求中不包含版本,也不会去掉版本
- AS_IN_REQUEST:原始请求中不包含版本,响应头就去掉版本
- ALWAYS_STRIP:始终会去掉版本
hostValue
参数:如果提供该值,将用于替换
host:port
响应
Location
头的值,如果为空,则使用请求中名为
Host
的header值。
protocolsRegex
参数是一个有效的正则字符串。如果不匹配,则过滤器不执行。默认值为http | https | ftp | ftps。
6.18 RewriteResponseHeader GatewayFilter Factory
接收
name
、
regexp
、
replacement
三个参数。使用Java正则表达式重写响应header头。
Example 43. application.yml
spring:cloud:gateway:routes:-id: rewriteresponseheader_route
uri: https://example.org
filters:- RewriteResponseHeader=X-Response-Red,, password=[^&]+, password=***
在下游响应返回到网关后,该示例将把
/42?user=ford&password=omg!what&flag=true
头的值,设置为
/42?user=ford&password=***&flag=true
。您必须使用
$\
代替
$
。
6.19 SaveSession GatewayFilter Factory
SaveSession GatewayFilter Factory将调用转发到下游之前强制执行
WebSession::save
操作。这在使用 Spring Session 之类时特别有用,需要确保会话状态在进行转发调用之前已保存。
Example 44. application.yml
spring:cloud:gateway:routes:-id: save_session
uri: https://example.org
predicates:- Path=/foo/**filters:- SaveSession
如果你希望要将Spring Security与Spring Session集成,并要确保安全信息都传到下游,这样做将是很重要的。
6.20 SecureHeaders GatewayFilter Factory
根据这篇blog的建议,SecureHeaders GatewayFilter Factory在response响应中添加了许多头。
添加了以下的头(默认值):
- 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
配置更改默认值:
- xss-protection-header
- strict-transport-security
- x-frame-options
- x-content-type-options
- referrer-policy
- content-security-policy
- x-download-options
- x-permitted-cross-domain-policies
使用
spring.cloud.gateway.filter.secure-headers.disable
禁用默认值,全小写逗号分割
6.21 SetPath GatewayFilter Factory
SetPath GatewayFilter Factory 采用一个
template
路径参数。它提供了一种简单的方法,通过允许路径的模板化segments来操作请求路径。使用Spring Framework中的URI模板,允许多个匹配segments。
Example 45. application.yml
spring:cloud:gateway:routes:-id: setpath_route
uri: https://example.org
predicates:- Path=/red/{segment}filters:- SetPath=/{segment}
如上所示:请求
/red/blue
,将在请求下游时将路径设置为
/blue
6.22 SetRequestHeader GatewayFilter Factory
采用
name
和
value
参数。
Example 46. application.yml
spring:cloud:gateway:routes:-id: setrequestheader_route
uri: https://example.org
filters:- SetRequestHeader=X-Request-Red, Blue
该GatewayFilter将会使用给定的name替换所有的header,而不是添加。因此会将请求头从
X-Request-Red:1234
设置为
X-Request-Red:Blue
。
SetRequestHeader
允许使用path或者host的URI变量。
Example 47. application.yml
spring:cloud:gateway:routes:-id: setrequestheader_route
uri: https://example.org
predicates:-Host:{segment}.myhost.org
filters:- SetRequestHeader=foo, bar-{segment}
6.23 SetResponseHeader GatewayFilter Factory
两个参数
name
和
value
。
Example 48. application.yml
spring:cloud:gateway:routes:-id: setresponseheader_route
uri: https://example.org
filters:- SetResponseHeader=X-Response-Red, Blue
该GatewayFilter将会使用给定的name替换所有的header,而不是添加。下游响应的头
X-Response-Red:1234
将会替换成
X-Response-Red:Blue
。
SetResponseHeader
也使用path或者host的URI变量。
Example 49. application.yml
spring:cloud:gateway:routes:-id: setresponseheader_route
uri: https://example.org
predicates:-Host:{segment}.myhost.org
filters:- SetResponseHeader=foo, bar-{segment}
6.24 SetStatus GatewayFilter Factory(演示)
接收一个参数
status
,必须是一个可用的Spring
HttpStatus
值,可用是整数或者枚举字符串。
Example 50. application.yml
spring:cloud:gateway:routes:-id: setstatusstring_route
uri: https://example.org
filters:- SetStatus=UNAUTHORIZED
-id: setstatusint_route
uri: https://example.org
filters:- SetStatus=401
该示例,将HTTP status响应头设置为401。
使用
SetStatus
可以在响应中返回代理请求中的原始Http 状态码。如下配置,将header添加到响应中。
Example 51. application.yml
spring:cloud:gateway:set-status:original-status-header-name: original-http-status
✅演示
如下示例配置了
original-status-header-name: original-http-status
和
SetStatus=401
,效果如下:
6.25 StripPrefix GatewayFilter Factory
接收一个
parts
参数。 parts参数指示在将请求发送到下游之前,要从请求中去除的路径中的节数。
Example 52. application.yml
spring:cloud:gateway:routes:-id: nameRoot
uri: https://nameservice
predicates:- Path=/name/**filters:- StripPrefix=2
该示例表示当网关发送
/name/blue/red
请求时,实际向下游请求的地址是
nameservice/red
。
6.26 Retry GatewayFilter Factory(演示)
Retry GatewayFilter Factory使用了reactor-addons 的retry组件进行重试,支持以下参数:
- retries:应尝试的重试次数
- statuses:应尝试的HTTP状态码
- methods:应尝试的HTTP方法
- series:应尝试的series状态码,
org.springframework.http.HttpStatus.Series
- exceptions:应尝试的异常列表
- backoff:配置指数退避重试。根据
firstBackoff * (factor ^ n)
进行指数重试,maxBackoff
限制最大退避重试,如果basedOnPreviousValue
为true,则退避指数计算使用prevBackoff * factor
。
Retry
过滤器默认值配置如下:
- retries: 3次
- series: 5XX series
- methods:GET 方法
- exceptions:IOException 和 TimeoutException
- backoff: disabled
Example 53. application.yml
spring:cloud:gateway:routes:-id: retry_test
uri: http://localhost:8080/flakey
predicates:- Host=*.retry.comfilters:-name: Retry
args:retries:3statuses: BAD_GATEWAY
methods: GET,POST
backoff:firstBackoff: 10ms
maxBackoff: 50ms
factor:2basedOnPreviousValue:false
❗️ 当重试过滤器与任何带body的HTTP请求使用时,body会被缓存。body被缓存在请求定义的的
ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR
中,对象类型是:
org.springframework.core.io.buffer.DataBuffer
。
使用单个
status
和
method
,可以使用简便的方式添加:
Example 54. application.yml
spring:cloud:gateway:routes:-id: retry_route
uri: https://example.org
filters:-name: Retry
args:retries:3statuses: INTERNAL_SERVER_ERROR
methods: GET
backoff:firstBackoff: 10ms
maxBackoff: 50ms
factor:2basedOnPreviousValue:false-id: retryshortcut_route
uri: https://example.org
filters:- Retry=3,INTERNAL_SERVER_ERROR,GET,10ms,50ms,2,false
✅演示
RetryGatewayFilter 示例教程演示
6.27 RequestSize GatewayFilter Factory
当请求大小大于允许的限制时,RequestSize GatewayFilter Factory可以限制请求不到达下游服务。过滤器以RequestSize作为参数,这是定义请求的允许大小限制(以字节为单位)。
Example 55. application.yml
spring:cloud:gateway:routes:-id: request_size_route
uri: http://localhost:8080/upload
predicates:- Path=/upload
filters:-name: RequestSize
args:maxSize:5000000
当请求因大小而被拒绝时, RequestSize GatewayFilter Factory 将响应状态设置为
413 Payload Too Large
,并带有额外的header
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
6.28 SetRequestHostHeader GatewayFilter Factory
接收一个
host
参数,用于覆盖主机头。
Example 56. application.yml
spring:cloud:gateway:routes:-id: set_request_host_header_route
uri: http://localhost:8080/headers
predicates:- Path=/headers
filters:-name: SetRequestHostHeader
args:host: example.org
该示例表示使用
example.org
代替host头的值。
6.29 ModifyRequestBodyGatewayFilterFactory
此过滤器可用于在请求主体被网关发送到下游之前对其进行修改。
❗️ 只能使用Java DSL配置此过滤器。如果没有body,
RewriteFilter
会传递null。
@BeanpublicRouteLocatorroutes(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)->returnMono.just(newHello(s.toUpperCase())))).uri(uri)).build();}staticclassHello{String message;publicHello(){}publicHello(String message){this.message = message;}publicStringgetMessage(){return message;}publicvoidsetMessage(String message){this.message = message;}}
6.30 Modify Response Body GatewayFilter Factory
此过滤器可用于在将响应正文发送回客户端之前对其进行修改。
❗️ 只能使用Java DSL配置此过滤器。如果没有body,
RewriteFilter
会传递null。
@BeanpublicRouteLocatorroutes(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();}
6.31 Token Relay GatewayFilter Factory
令牌中继是OAuth2使用者充当客户端并将传入令牌转发给传出资源请求的地方。使用者可以是纯客户端(如SSO应用程序)或资源服务器。
Spring Cloud Gateway 可以将OAuth2访问令牌转发到其代理的服务下游。要将此功能添加到网关,您需要添加
TokenRelayGatewayFilterFactory
。
App.java
@BeanpublicRouteLocatorcustomRouteLocator(RouteLocatorBuilder builder){return builder.routes().route("resource", r -> r.path("/resource").filters(f -> f.tokenRelay()).uri("http://localhost:9000")).build();}
或者
application.yaml
spring:cloud:gateway:routes:-id: resource
uri: http://localhost:9000predicates:- Path=/resource
filters:- TokenRelay=
它将(除了让登录和获取令牌之外)将身份验证令牌传递给下游的服务(在本例中是
/resource
)。
开启该功能要添加依赖到Spring Cloud Gateway
- org.springframework.boot:spring-boot-starter-oauth2-client
工作原理:TokenRelayGatewayFilterFactory会从认证的用户中提取access token,并放入发送给下游的请求中。示例见:thi project.
❗️ ReactiveOAuth2AuthorizedClientService的默认实现是TokenRelayGatewayFilterFactory,使用内存存储,如果需要自定义,需要自己实现ReactiveOAuth2AuthorizedClientService 。
6.32 CacheRequestBody GatewayFilter Factory
由于请求body流只能读取一次,因此我们需要缓存请求的body。可以使用
CacheRequestBody
缓存body,并从exchange 中获取该body。
@BeanpublicRouteLocatorroutes(RouteLocatorBuilder builder){return builder.routes().route("cache_request_body_route", r -> r.path("/downstream/**").filters(f -> f.prefixPath("/httpbin").cacheRequestBody(String.class).uri(uri)).build();}
Example 57. application.yml
spring:cloud:gateway:routes:-id: cache_request_body_route
uri: lb://downstream
predicates:- Path=/downstream/**filters:-name: CacheRequestBody
args:bodyClass: java.lang.String
CacheRequestBody
将提取请求body并转换成body 指定的类。(本例中是java.lang.String)。缓存中定义的key为
ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR
。
❗️ 仅支持http/https 请求
6.33 Default Filters
可以使用
spring.cloud.gateway.default-filters
作为所有路由的过滤器。该配置接收一个filter列表,如下:
Example 58. application.yml
spring:cloud:gateway:default-filters:- AddResponseHeader=X-Response-Default-Red, Default-Blue
- PrefixPath=/httpbin
7. Global Filters
GlobalFilter接口与GatewayFilter具有相同的签名。是有条件地应用于所有路由的特殊过滤器。
❗️ 此接口和用法可能在将来的里程碑版本中发生更改
7.1 全局Filter和GatewayFilter组合排序
当请求匹配到路由时,web 过滤处理器会将所有的
GlobalFilter
实例和指定的
GatewayFilter
实例添加到过滤器链。filter的排序由
org.springframework.core.Ordered
接口决定,可以通过
getOrder()
方法或者@Order注释来设置。
由于Spring Cloud Gateway将用于执行过滤器逻辑区分为“前置”和“后置”阶段,具有最高优先级的过滤器将是“前置”阶段的第一个,而“后置”阶段的最后一个。
如下配置了一个过滤器链:
Example 59. ExampleConfiguration.java
@BeanpublicGlobalFiltercustomFilter(){returnnewCustomGlobalFilter();}publicclassCustomGlobalFilterimplementsGlobalFilter,Ordered{@OverridepublicMono<Void>filter(ServerWebExchange exchange,GatewayFilterChain chain){
log.info("custom global filter");return chain.filter(exchange);}@OverridepublicintgetOrder(){return-1;}}
7.2 Forward Routing Filter
ForwardRoutingFilter在exchange属性
ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
中查找URI。如果URL有一个
forward
scheme (如
forward:///localendpoint
),它将使用Spring
DispatcherHandler
来处理请求。请求URL的路径部分将被转发URL中的路径覆盖。未修改的原始URL将附加到
ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR
属性中的列表中。
7.3 ReactiveLoadBalancerClientFilter
ReactiveLoadBalancerClientFilter在exchange属性
ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
中查找URI。如果URL有一个
lb
scheme (如
lb://myservice
),它将使用Spring Cloud ReactorLoadBalancer 将名称(在前一个示例中为
myservice
)解析为实际主机和端口,并替换URI。未修改的原始URL将附加到
ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR
属性中的列表中。过滤器还将查看
ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR
属性,查看它是否等于
lb
,然后应用相同的规则。
Example 60. application.yml
spring:cloud:gateway:routes:-id: myRoute
uri: lb://service
predicates:- Path=/service/**
❗️默认情况下,如果一个服务实例在ReactorLoadBalancer中没有发现,则返回503。可以通过设置
spring.cloud.gateway.loadbalancer.use404=true
来让网关返回404.
❗️从ReactiveLoadBalancerClientFilter 返回的ServiceInstance的isSecure 值将覆盖在对网关发出的请求中指定的scheme。例如,如果请求通过HTTPS进入网关,但ServiceInstance表示它不安全,则下游请求将通过HTTP协议。相反的情况也适用。但是,如果在网关配置中为路由指定了
GATEWAY_SCHEME_PREFIX_ATTR
,则前缀将被删除,并且路由URL生成的scheme将覆盖ServiceInstance配置。
💡 Gateway支持所有LoadBalancer 能力。详情查看Spring Cloud Commons documentation.
7.4 Netty Routing Filter
如果位于
ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
属性中的URL具有http 或https 模式,则会运行Netty Routing Filter。它使用Netty HttpClient 发出下游代理请求。响应放在
ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR
exchange属性中,以便在以后的过滤器中使用。(有一个处于实验阶段的
WebClientHttpRoutingFilter
,不需要使用Netty)。
7.5 Netty Write Response Filter
如果
ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR exchange
属性中存在
Netty HttpClientResponse
,则运行
NettyWriteResponseFilter
。它在其他所有过滤器完成后运行,并将代理响应写回到网关客户端的响应中。(一个处于实验阶段的,不需要Netty的过滤器
WebClientWriteResponseFilter
)
7.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
中,以便稍后在过滤器链中使用。
7.7 Websocket Routing Filter
如果
ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
exchange属性中有
ws
、
wss
scheme,则Websocket Routing Filter将被运行。它使用Spring Web Socket基础模块将Websocket转发到下游。
URI前缀为
lb
的Websockets可以被负载均衡,如
lb:ws://serviceid
。
❗️ 如果使用 SockJS 作为普通HTTP的fallback,则应配置普通HTTP路由以及WebSocket路由。
Example 61. application.yml
spring:cloud:gateway:routes:# SockJS route-id: websocket_sockjs_route
uri: http://localhost:3001predicates:- Path=/websocket/info/**# Normal Websocket route-id: websocket_route
uri: ws://localhost:3001predicates:- Path=/websocket/**
7.8 Gateway Metrics Filter
要启用网关指标,请将
spring-boot-starter-actuator
添加为项目依赖项。然后,默认情况下,只要属性
spring.cloud.gateway.metrics.enabled
未设置为
false
,网关指标过滤器就会运行。此过滤器添加名为
spring.cloud.gateway.requests
的计时器指标,并带有以下标记:
- routeId: route ID.
- routeUri: API 将被转发的URI
- outcome: 结果分类,依据 HttpStatus.Series
- status: 返回client的请求的Http Status
- httpStatusCode: 返回client的请求的httpStatusCode
- httpMethod: 用于请求的HTTP方法
另外通过
spring.cloud.gateway.metrics.tags.path.enabled
(默认为false)来激活额外的指标:
- path:请求的路径
这些指标可以从
/actuator/metrics/spring.cloud.gateway.requests
获取,并且能够很容易的与Prometheus 集成创建Grafana dashboard。
❗️ 要将pometheus启用,需要添加
micrometer-registry-prometheus
为项目依赖。
7.9 Marking An Exchange As Routed
网关路由
ServerWebExchange
之后,它将通过向Exchange属性添加
gatewayAlreadyRouted
,将该exchange标记为“routed”。一旦一个请求被标记为routed,其他路由过滤器将不会再次路由该请求,将跳过该过滤器。有一些方便的方法可以用来将exchange标记为routed,或者检查exchange是否已经routed。
- ServerWebExchangeUtils.isAlreadyRouted 有一个
ServerWebExchange
对象用来检查是否已routed。 - ServerWebExchangeUtils.setAlreadyRouted 有一个
ServerWebExchange
对象来标记是否routed。
8. HttpHeadersFilters
HttpHeadersFilters使用在请求被发送到下游之前,比如在
NettyRoutingFilter
中使用到了。
8.1 Forwarded Headers Filter
Forwarded Headers Filter
创建一个
Forwarded
头到发送给下游的请求中。它使用当前请求的
Host
头,scheme 和端口添加到任何现有的Forwarded 头中。
8.2 RemoveHopByHop Headers Filter
RemoveHopByHop
用来在请求中删除头信息。删除的默认标头列表来自IETF。
默认删除的头信息:
- Connection
- Keep-Alive
- Proxy-Authenticate
- Proxy-Authorization
- TE
- Trailer
- Transfer-Encoding
- Upgrade
要更改此设置,通过
spring.cloud.gateway.filter.remove-hop-by-hop.headers
配置要删除的头信息。
8.3 XForwarded Headers Filter
XForwarded Headers Filter 创建各种
X-Forwarded-*
头以发送到下游服务。它使用当前请求的Host 头、scheme、port和path来创建各种头信息。
可以通过布尔属性(默认true)来配置单个的header:
- spring.cloud.gateway.x-forwarded.for-enabled
- spring.cloud.gateway.x-forwarded.host-enabled
- spring.cloud.gateway.x-forwarded.port-enabled
- spring.cloud.gateway.x-forwarded.proto-enabled
- spring.cloud.gateway.x-forwarded.prefix-enabled
附加多个标头可以由以下布尔属性控制(默认为true):
- spring.cloud.gateway.x-forwarded.for-append
- spring.cloud.gateway.x-forwarded.host-append
- spring.cloud.gateway.x-forwarded.port-append
- spring.cloud.gateway.x-forwarded.proto-append
- spring.cloud.gateway.x-forwarded.prefix-append
9. TLS and SSL
网关可以通过常规的 Spring server configuration 来侦听HTTPS上的请求。
Example 62. application.yml
server:ssl:enabled:truekey-alias: scg
key-store-password: scg1234
key-store: classpath:scg-keystore.p12
key-store-type: PKCS12
网关路由可以路由到HTTP和HTTPS后端。如果路由到HTTPS后端,则可以将网关配置为信任所有具有证书的下游服务:
Example 63. application.yml
spring:cloud:gateway:httpclient:ssl:useInsecureTrustManager:true
不建议在生产环境使用不安全的信任管理器。对于生产部署,可以使用一组已知证书配置网关,这些证书可以通过以下方式进行配置:
Example 64. application.yml
spring:cloud:gateway:httpclient:ssl:trustedX509Certificates:- cert1.pem
- cert2.pem
如果Spring Cloud Gateway未配置受信任证书,则使用默认信任库(可以使用系统属性
javax.net.ssl.trustStore
覆盖)。
9.1 TLS握手
网关会维护一个用于路由到后端的client池。当通过HTTPS通信时,客户端启动一个TLS握手,其中可能会有很多超时。这些超时可以这样配置(显示默认值):
Example 65. application.yml
spring:cloud:gateway:httpclient:ssl:handshake-timeout-millis:10000close-notify-flush-timeout-millis:3000close-notify-read-timeout-millis:0
10. Configuration
Spring Cloud Gateway的配置由
RouteDefinitionLocator
的集合实例驱动。如下是
RouteDefinitionLocator
的接口:
Example 66. RouteDefinitionLocator.java
publicinterfaceRouteDefinitionLocator{Flux<RouteDefinition>getRouteDefinitions();}
默认情况下,
PropertiesRouteDefinitionLocator
使用Spring Boot的
@ConfigurationProperties
机制加载属性。
以下两个方式等效:
Example 67. application.yml
spring:cloud:gateway:routes:-id: setstatus_route
uri: https://example.org
filters:-name: SetStatus
args:status:401-id: setstatusshortcut_route
uri: https://example.org
filters:- SetStatus=401
对于网关的大部分用法,配置文件方式是够用的,但一些生产用例更建议从外部源(如数据库)加载配置。未来的里程碑版本将有基于Spring Data Repositories (如Redis、MongoDB和Cassandra)的RouteDefinitionLocator实现。
10.1 RouteDefinition Metrics
开启
RouteDefinition
,需要添加spring-boot-starter-actuator依赖。默认
spring.cloud.gateway.metrics.enabled
指标是设置为
true
。名为
spring.cloud.gateway.routes.count
的指标,其值为RouteDefinitions的值。指标路径
/actuator/metrics/spring.cloud.gateway.routes.count
。
11. Route Metadata Configuration
您可以使用metadata为每个路由配置其他参数,如下所示:
Example 68. application.yml
spring:cloud:gateway:routes:-id: route_with_metadata
uri: https://example.org
metadata:optionName:"OptionValue"compositeObject:name:"value"iAmNumber:1
您可以从exchange获取所有元数据属性,如下所示:
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);// get all metadata properties
route.getMetadata();// get a single metadata property
route.getMetadata(someKey);
12. Http超时配置
12.1 全局超时
connect-timeout
必填,毫秒
response-timeout
必填,类型为 java.time.Duration
global http timeouts example
spring:cloud:gateway:httpclient:connect-timeout:1000response-timeout: 5s
12.2 Per-route timeouts
connect-timeout
必填,毫秒
response-timeout
必填,毫秒
-id: per_route_timeouts
uri: https://example.org
predicates:-name: Path
args:pattern: /delay/{timeout}metadata:response-timeout:200connect-timeout:200
使用Java DSL配置 pre-route超时
importstaticorg.springframework.cloud.gateway.support.RouteMetadataUtils.CONNECT_TIMEOUT_ATTR;importstaticorg.springframework.cloud.gateway.support.RouteMetadataUtils.RESPONSE_TIMEOUT_ATTR;@BeanpublicRouteLocatorcustomRouteLocator(RouteLocatorBuilder routeBuilder){return routeBuilder.routes().route("test1", r ->{return r.host("*.somehost.org").and().path("/somepath").filters(f -> f.addRequestHeader("header1","header-value-1")).uri("http://someuri").metadata(RESPONSE_TIMEOUT_ATTR,200).metadata(CONNECT_TIMEOUT_ATTR,200);}).build();}
per-route 的
response-timeout
为赋值的时候,全局的
response-timeout
将被禁用。
-id: per_route_timeouts
uri: https://example.org
predicates:-name: Path
args:pattern: /delay/{timeout}metadata:response-timeout:-1
12.3 流式Java Routes API
RouteLocatorBuilder
具备流式API功能。
Example 69. GatewaySampleApplication.java
// static imports from GatewayFilters and RoutePredicates@BeanpublicRouteLocatorcustomRouteLocator(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").metadata("key","value")).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").metadata("key","value")).build();}
这种风格运行更多的自定义断言,RouteDefinitionLocator 断言通过and组合。另外使用流式API,您可以使用and(), or(), 和negate()操作Predicate类。
12.4 DiscoveryClient Route Definition Locator
基于在DiscoveryClient兼容服务注册表中注册的服务创建路由。
使用
spring.cloud.gateway.discovery.locator.enabled=true
开启它,并确保DiscoveryClient 实现组件(比如Netflix Eureka, Consul, or Zookeeper)在类路径中。
12.4.1 Configuring Predicates and Filters For DiscoveryClient Routes
Example 70. 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: CircuitBreaker
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}'"
13. Reactor Netty 访问日志
开启该访问日志,设置
-Dreactor.netty.http.server.accessLogEnabled=true
。
❗️ 它是一个Java 系统配置,而不是Spring Boot的配置。
您可以将日志记录系统配置为单独的访问日志文件。以下示例创建了一个Logback配置:
Example 71. logback.xml
<appendername="accessLog"class="ch.qos.logback.core.FileAppender"><file>access_log.log</file><encoder><pattern>%msg%n</pattern></encoder></appender><appendername="async"class="ch.qos.logback.classic.AsyncAppender"><appender-refref="accessLog"/></appender><loggername="reactor.netty.http.server.AccessLog"level="INFO"additivity="false"><appender-refref="async"/></logger>
14.CORS配置
我们可以通过配置网关来控制CORS行为,全局CORS配置是 Spring Framework CorsConfiguration模式的URL MAP。
Example 72. application.yml
spring:cloud:gateway:globalcors:cors-configurations:'[/**]':allowedOrigins:"https://docs.spring.io"allowedMethods:- GET
例子中将允许从docs.spring.io发出的所有GET请求进行CORS请求。
15. Actuator API
/gateway
的actuator端点允许监视Spring Cloud Gateway并与之交互。要进行远程访问,必须在应用程序属性中暴露HTTP或JMX 端口。
Example 73. application.properties
management.endpoint.gateway.enabled=true # default value
management.endpoints.web.exposure.include=gateway
15.1 Verbose Actuator Format
它为每个路由添加了更多细节,允许您查看与每个路由相关联的谓词和过滤器以及可用的任何配置。
[{"predicate":"(Hosts: [**.addrequestheader.org] && Paths: [/headers], match trailing slash: true)","route_id":"add_request_header_test","filters":["[[AddResponseHeader X-Response-Default-Foo = 'Default-Bar'], order = 1]","[[AddRequestHeader X-Request-Foo = 'Bar'], order = 1]","[[PrefixPath prefix = '/httpbin'], order = 2]"],"uri":"lb://testservice","order":0}]
该功能默认开启,如下设置禁用
Example 74. application.properties
spring.cloud.gateway.actuator.verbose.enabled=false
15.2 查询 Route Filters
15.2.1 Global Filters
要查询用于所有路由的全局filter,需要发送一个
GET
请求到
/actuator/gateway/globalfilters
。结果响应类似于以下内容:
{"org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@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}
对于每个全局过滤器,使用过滤器对象字符串表示,后面数字表示过滤器顺序。
15.2.2 Route Filters
要查询gateway Filters ,需要发送一个
GET
请求到
/actuator/gateway/routefilters
。
结果响应类似于以下内容:
{"[AddRequestHeaderGatewayFilterFactory@570ed9c configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]":null,"[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]":null,"[SaveSessionGatewayFilterFactory@4449b273 configClass = Object]":null}
每个工厂都有对应对象的字符串表示。
null
是由于端点控制器的实现不完整,因为它试图设置过滤器链中对象的顺序,但这不适用于GatewayFilter工厂对象。
15.3 刷新 Route Cache
清除route cache ,发送
POST
请求到
/actuator/gateway/refresh
。请求返回一个200,没有响应主体。
15.4 检索网关中定义的路由
要检索网关中定义的路由,请向
/actuator/gateway/routes
发出
GET
请求。结果响应类似于以下内容:
[{"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}]
响应包含网关中定义的所有路由的详细信息。下表描述了响应的每个元素(每个元素都是一个路由)的结构:
PathTypeDescription
route_id
Stringroute ID.
route_object.predicate
Objectroute 断言.
route_object.filters
Array应用到该路由的 GatewayFilter factories
order
Numberroute order.
15.5 检索有关特定路由的信息
要获取单个路由的信息,发送
GET
请求
/actuator/gateway/routes/{id}
(如:
/actuator/gateway/routes/first_route
),返回结果如下所示:
{"id":"first_route","predicates":[{"name":"Path","args":{"_genkey_0":"/first"}}],"filters":[],"uri":"https://www.uri-destination.org","order":0}
下面表格中描述了返回结果信息:
PathTypeDescription
id
Stringroute ID.
predicates
Array路由断言的集合。每个项定义给定断言的名称和参数。
filters
Array应用于路由的过滤器器集合。
uri
String路由的目标URI
order
Numberroute order.
15.6 创建和删除特定路由
要创建一个路由,发送
POST
请求
/gateway/routes/{id_route_to_create}
,参数为JSON结构,具体参数数据结构参考上面章节。
要删除一个路由,发送
DELETE
请求
/gateway/routes/{id_route_to_delete}
。
15.7 所有端点列表
下表总结了Spring Cloud Gateway启动器端点(注意,每个端点都有/actuator/gateway作为基础路径):
IDHTTP MethodDescription
globalfilters
GETDisplays the list of global filters applied to the routes.
routefilters
GETDisplays the list of
GatewayFilter
factories applied to a particular route.
refresh
POSTClears the routes cache.
routes
GETDisplays the list of routes defined in the gateway.
routes/{id}
GETDisplays information about a particular route.
routes/{id}
POSTAdds a new route to the gateway.
routes/{id}
DELETERemoves an existing route from the gateway.
15.8 多个网关实例之间共享路由
Spring Cloud Gateway 提供了两个
RouteDefinitionRepository
实现。第一个是
RouteDefinitionRepository
它只存在于一个网关实例的内存中。这种类型的存储库不适合跨多个网关实例填充路由。
为了能够共享路由,可以使用
RedisRouteDefinitionRepository
。要启用此类存储库,必须将以下属性设置为true:
spring.cloud.gateway.redis-route-definition-repository.enabled
,它需要使用spring-boot-starter-data-redis-reactive Spring Boot starter。
16. 故障诊断
16.1 Log Levels
以下日志可能包含debug和trace级别的有价值的故障排除信息:
org.springframework.cloud.gateway
org.springframework.http.server.reactive
org.springframework.web.reactive
org.springframework.boot.autoconfigure.web
reactor.netty
redisratelimiter
16.2 Wiretap
Reactor Netty HttpClient 以及 HttpServer 可启用 Wiretap 。将reactor.netty 包设置成 debug 或 trace ,然后设置如下属性:
spring.cloud.gateway.httpserver.wiretap=true
spring.cloud.gateway.httpclient.wiretap=true
分别开启HttpServer及HttpClient的Wiretap。
17 开发者指南
编写网关自定义组件基本指南。
17.1 自定义Route Predicate Factories
实现
RoutePredicateFactory
作为bean,有一个
AbstractRoutePredicateFactory
抽象类用于扩展。
MyRoutePredicateFactory.java
@ComponentpublicclassMyRoutePredicateFactoryextendsAbstractRoutePredicateFactory<MyRoutePredicateFactory.Config>{publicMyRoutePredicateFactory(){super(Config.class);}@OverridepublicPredicate<ServerWebExchange>apply(Config config){// grab configuration from Config objectreturn exchange ->{//grab the requestServerHttpRequest request = exchange.getRequest();//take information from the request to see if it//matches configuration.returnmatches(config, request);};}publicstaticclassConfig{//Put the configuration properties for your filter here}}
17.2 自定义GatewayFilter Factories
实现
GatewayFilterFactory
作为一个bean,有一个抽象类
AbstractGatewayFilterFactory
用来扩展。
Example 75. PreGatewayFilterFactory.java
@ComponentpublicclassPreGatewayFilterFactoryextendsAbstractGatewayFilterFactory<PreGatewayFilterFactory.Config>{publicPreGatewayFilterFactory(){super(Config.class);}@OverridepublicGatewayFilterapply(Config config){// grab configuration from Config objectreturn(exchange, chain)->{//If you want to build a "pre" filter you need to manipulate the//request before calling chain.filterServerHttpRequest.Builder builder = exchange.getRequest().mutate();//use builder to manipulate the requestreturn chain.filter(exchange.mutate().request(builder.build()).build());};}publicstaticclassConfig{//Put the configuration properties for your filter here}}
PostGatewayFilterFactory.java
@ComponentpublicclassPostGatewayFilterFactoryextendsAbstractGatewayFilterFactory<PostGatewayFilterFactory.Config>{publicPostGatewayFilterFactory(){super(Config.class);}@OverridepublicGatewayFilterapply(Config config){// grab configuration from Config objectreturn(exchange, chain)->{return chain.filter(exchange).then(Mono.fromRunnable(()->{ServerHttpResponse response = exchange.getResponse();//Manipulate the response in some way}));};}publicstaticclassConfig{//Put the configuration properties for your filter here}}
17.2.1 在配置中命名自定义过滤器和引用
自定义过滤器类名应以GatewayFilterFactory结尾。
例如,要引用配置文件中名为Something 的过滤器,该过滤器必须位于名为
SomethingGatewayFilterFactory
的类中。
17.3 自定义 Global Filters
实现
GlobalFilter
作为bean。
以下示例分别显示了如何设置全局前置和后置过滤器:
//前置@BeanpublicGlobalFiltercustomGlobalFilter(){return(exchange, chain)-> exchange.getPrincipal().map(Principal::getName).defaultIfEmpty("Default User").map(userName ->{//adds header to proxied request
exchange.getRequest().mutate().header("CUSTOM-REQUEST-HEADER", userName).build();return exchange;}).flatMap(chain::filter);}//后置@BeanpublicGlobalFiltercustomGlobalPostFilter(){return(exchange, chain)-> chain.filter(exchange).then(Mono.just(exchange)).map(serverWebExchange ->{//adds header to response
serverWebExchange.getResponse().getHeaders().set("CUSTOM-RESPONSE-HEADER",HttpStatus.OK.equals(serverWebExchange.getResponse().getStatusCode())?"It worked":"It did not work");return serverWebExchange;}).then();}
18. 构建简单网关示例(略)
19. 配置属性
所有与Spring Cloud Gateway相关的配置列表
版权归原作者 阿提说说 所有, 如有侵权,请联系我们删除。