Spring Cloud Gateway
本项目提供了一个构建在 Spring 生态之上的 API Gateway,包括:Spring 5、Spring Boot 2 和 Project Reactor。Spring Cloud Gateway 旨在提供一种简单而有效的方式来路由到 API,并为它们提供横切关注点,例如:安全性、监控/指标和弹性。
如何包含Spring Cloud Gateway
要将 Spring Cloud Gateway 包含在您的项目中,请使用组 IDorg.springframework.cloud
和工件 ID 的启动器spring-cloud-starter-gateway
。
如果包含启动器,但不希望启用网关,请设置spring.cloud.gateway.enabled=false
.
Spring Cloud Gateway 需要 Spring Boot 和 Spring Webflux 提供的 Netty 运行时。它不适用于传统的 Servlet 容器或构建为 WAR 时。
词汇表
- Route:网关的基本构建块。它由 ID、目标 URI、谓词集合和过滤器集合定义。如果聚合谓词为真,则匹配路由。
-
谓词:这是一个Java 8 函数谓词。输入类型是Spring Framework
ServerWebExchange
。这使您可以匹配来自 HTTP 请求的任何内容,例如标头或参数。 -
过滤器
GatewayFilter
:这些是使用特定工厂构建的实例。在这里,您可以在发送下游请求之前或之后修改请求和响应。
它是如何工作的
下图提供了 Spring Cloud Gateway 如何工作的高级概述:
客户端向 Spring Cloud Gateway 发出请求。如果网关处理程序映射确定请求与路由匹配,则将其发送到网关 Web 处理程序。此处理程序通过特定于请求的过滤器链运行请求。过滤器用虚线划分的原因是过滤器可以在发送代理请求之前和之后运行逻辑。执行所有“预”过滤器逻辑。然后发出代理请求。发出代理请求后,将运行“发布”过滤器逻辑。
配置路由谓词工厂和网关过滤工厂
有两种配置谓词和过滤器的方法:快捷方式和完全扩展的参数。下面的大多数示例都使用快捷方式。
名称和参数名称将code
在每个部分的第一句或第二句中列出。参数通常按快捷方式配置所需的顺序列出。
快捷方式配置
快捷方式配置由过滤器名称识别,后跟等号 ( =
),后跟以逗号 ( ,
) 分隔的参数值。
应用程序.yml
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- Cookie=mycookie,mycookievalue
前面的示例Cookie
使用两个参数定义了路由谓词工厂,cookie 名称mycookie
和要匹配的值mycookievalue
。
完全扩展的参数
完全扩展的参数看起来更像是带有名称/值对的标准 yaml 配置。通常,会有一把name
钥匙和一把args
钥匙。键是用于配置谓词或过滤器的args
键值对映射。
应用程序.yml
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- name: Cookie
args:
name: mycookie
regexp: mycookievalue
Cookie
这是上面显示的谓词的快捷配置的完整配置。
路由谓词工厂
Spring Cloud Gateway 将路由匹配为 Spring WebFluxHandlerMapping
基础架构的一部分。Spring Cloud Gateway 包含许多内置的路由谓词工厂。所有这些谓词都匹配 HTTP 请求的不同属性。您可以将多个路由谓词工厂与逻辑and
语句结合起来。
After Route 谓词工厂
所述After
路线谓词工厂有一个参数,一个datetime
(其是Java ZonedDateTime
)。此谓词匹配在指定日期时间之后发生的请求。以下示例配置了一个 after 路由谓词:
示例 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]
此路线匹配 2017 年 1 月 20 日 17:42 Mountain Time(丹佛)之后提出的任何请求。
Before 路由谓词工厂
所述Before
路线谓词工厂有一个参数,一个datetime
(其是Java ZonedDateTime
)。此谓词匹配在指定的 之前发生的请求datetime
。以下示例配置了一个 before 路由谓词:
示例 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]
此路线与 2017 年 1 月 20 日 17:42 Mountain Time (Denver) 之前提出的任何请求相匹配。
Between 谓词工厂
该Between
路线谓词工厂有两个参数,datetime1
并且datetime2
这是JavaZonedDateTime
对象。此谓词匹配发生在 afterdatetime1
和 before 的请求datetime2
。该datetime2
参数必须是后datetime1
。以下示例配置了一个 between 路由谓词:
示例 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]
此路线匹配 2017 年 1 月 20 日 17:42 山区时间(丹佛)和 2017 年 1 月 21 日 17:42 山区时间(丹佛)之前提出的任何请求。这对于维护窗口可能很有用。
Cookie 路由谓词工厂
Cookie
路由谓词工厂有两个参数,cookie和name
a regexp
(这是一个 Java 正则表达式)。此谓词匹配具有给定名称且其值与正则表达式匹配的 cookie。以下示例配置 cookie 路由谓词工厂:
示例 4.application.yml
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p
此路由匹配具有名为chocolate
其值与ch.p
正则表达式匹配的 cookie 的请求。
标头路由谓词工厂
Header
路由谓词工厂有两个参数,the和header
a regexp
(这是一个 Java 正则表达式)。此谓词与具有给定名称且值与正则表达式匹配的标头匹配。以下示例配置了一个标头路由谓词:
示例 5.application.yml
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://example.org
predicates:
- Header=X-Request-Id, \d+
如果请求具有一个名为X-Request-Id
其值与\d+
正则表达式匹配的标头(即,它具有一个或多个数字的值),则此路由匹配。
主机路由谓词工厂
该Host
路线谓词工厂需要一个参数:主机名的列表patterns
。该模式是一种 Ant 风格的模式,.
以分隔符为分隔符。此谓词匹配Host
与模式匹配的标头。以下示例配置主机路由谓词:
示例 6.application.yml
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Host=**.somehost.org,**.anotherhost.org
{sub}.myhost.org
还支持URI 模板变量(例如)。
如果请求具有Host
值为www.somehost.org
orbeta.somehost.org
或的标头,则此路由匹配www.anotherhost.org
。
此谓词将 URI 模板变量(例如sub
,在前面的示例中定义)提取为名称和值的映射,并将其放置在 中,ServerWebExchange.getAttributes()
其中的键定义为ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE
。然后这些值可供GatewayFilter
工厂使用
方法路由谓词工厂
Method
Route Predicate Factory 接受一个参数,该methods
参数是一个或多个参数:要匹配的 HTTP 方法。以下示例配置方法路由谓词:
示例 7.application.yml
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST
GET
如果请求方法是 a或 a ,则此路由匹配POST
。
路径路由谓词工厂
Path
Route Predicate Factory 有两个参数:一个 Spring 列表PathMatcher
patterns
和一个名为matchTrailingSlash
(默认为)的可选标志true
。以下示例配置路径路由谓词:
示例 8.application.yml
spring:
cloud:
gateway:
routes:
- id: path_route
uri: https://example.org
predicates:
- Path=/red/{segment},/blue/{segment}
如果请求路径是,则此路由匹配,例如:/red/1
or/red/1/
或/red/blue
or /blue/green
。
如果matchTrailingSlash
设置为false
,则请求路径/red/1/
将不匹配。
此谓词将 URI 模板变量(例如segment
,在前面的示例中定义)提取为名称和值的映射,并将其放置在 中,ServerWebExchange.getAttributes()
其中的键定义为ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE
。然后这些值可供GatewayFilter
工厂使用
可以使用一种实用方法(称为get
)来更轻松地访问这些变量。以下示例显示了如何使用该get
方法:
Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);
String segment = uriVariables.get("segment");
查询路由谓词工厂
Query
路由谓词工厂有两个参数:一个必需的param
和一个可选的regexp
(它是一个 Java 正则表达式)。以下示例配置查询路由谓词:
示例 9.application.yml
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=green
如果请求包含green
查询参数,则前面的路由匹配。
应用程序.yml
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=red, gree.
如果请求包含red
其值与正则gree.
表达式匹配的查询参数,则前面的路由匹配,因此green
并且greet
会匹配。
RemoteAddr 路由谓词工厂
路由谓词工厂采用的RemoteAddr
列表(最小大小为 1)sources
,它们是 CIDR 表示法(IPv4 或 IPv6)字符串,例如192.168.0.1/16
(其中192.168.0.1
是 IP 地址和16
子网掩码)。以下示例配置 RemoteAddr 路由谓词:
示例 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
。
修改远程地址的解析方式
默认情况下,RemoteAddr 路由谓词工厂使用来自传入请求的远程地址。如果 Spring Cloud Gateway 位于代理层后面,这可能与实际客户端 IP 地址不匹配。
您可以通过设置自定义来自定义解析远程地址的方式RemoteAddressResolver
。Spring Cloud Gateway 带有一个基于X-Forwarded-For 标头的非默认远程地址解析器,XForwardedRemoteAddressResolver
.
XForwardedRemoteAddressResolver
有两个静态构造方法,它们采用不同的安全方法:
-
XForwardedRemoteAddressResolver::trustAll
返回RemoteAddressResolver
始终采用在X-Forwarded-For
标头中找到的第一个 IP 地址的 a。这种方法容易受到欺骗,因为恶意客户端可以为 设置初始值,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 |
结果 |
---|---|
[ Integer.MIN_VALUE ,0] |
(无效,IllegalArgumentException 初始化期间) |
1 | 0.0.0.3 |
2 | 0.0.0.2 |
3 | 0.0.0.1 |
[4, Integer.MAX_VALUE ] |
0.0.0.1 |
以下示例显示了如何使用 Java 实现相同的配置:
示例 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")
)
权重路线谓词工厂
Weight
路由谓词工厂有两个参数:和group
(weight
一个 int)。权重是按组计算的。以下示例配置权重路由谓词:
示例 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
GatewayFilter
工厂
路由过滤器允许以某种方式修改传入的 HTTP 请求或传出的 HTTP 响应。路由过滤器的范围是特定的路由。Spring Cloud Gateway 包含许多内置的 GatewayFilter 工厂。
AddRequestHeader
AddRequestHeader
GatewayFilter
工厂采用name 和参数
value。以下示例配置一个
AddRequestHeaderGatewayFilter`:
示例 13.application.yml
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
filters:
- AddRequestHeader=X-Request-red, blue
此清单将X-Request-red:blue
标头添加到所有匹配请求的下游请求标头中。
AddRequestHeader
知道用于匹配路径或主机的 URI 变量。URI 变量可以在值中使用并在运行时扩展。以下示例配置AddRequestHeader
GatewayFilter
使用变量的 an:
示例 14.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}
AddRequestParameter
AddRequestParameter
GatewayFilter
Factory 采用andname
参数value
。以下示例配置一个AddRequestParameter
GatewayFilter
:
示例 15.application.yml
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: https://example.org
filters:
- AddRequestParameter=red, blue
这将添加red=blue
到所有匹配请求的下游请求的查询字符串中。
AddRequestParameter
知道用于匹配路径或主机的 URI 变量。URI 变量可以在值中使用并在运行时扩展。以下示例配置AddRequestParameter
GatewayFilter
使用变量的 an:
示例 16.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}
AddResponseHeader
AddResponseHeader
GatewayFilter
Factory 采用andname
参数value
。以下示例配置一个AddResponseHeader
GatewayFilter
:
示例 17.application.yml
spring:
cloud:
gateway:
routes:
- id: add_response_header_route
uri: https://example.org
filters:
- AddResponseHeader=X-Response-Red, Blue
这会将X-Response-Red:Blue
标头添加到所有匹配请求的下游响应标头中。
AddResponseHeader
知道用于匹配路径或主机的 URI 变量。URI 变量可以在值中使用并在运行时扩展。以下示例配置AddResponseHeader
GatewayFilter
使用变量的 an:
示例 18.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}
DedupeResponseHeader
DedupeResponseHeader GatewayFilter 工厂接受一个name
参数和一个可选strategy
参数。name
可以包含以空格分隔的标题名称列表。以下示例配置了一个DedupeResponseHeader
GatewayFilter
:
示例 19.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
在网关 CORS 逻辑和下游逻辑都添加它们的情况下,这将删除重复值Access-Control-Allow-Credentials
和响应标头。Access-Control-Allow-Origin
过滤器DedupeResponseHeader
还接受一个可选strategy
参数。接受的值为RETAIN_FIRST
(默认)RETAIN_LAST
、 和RETAIN_UNIQUE
。
Spring Cloud CircuitBreaker
Spring Cloud CircuitBreaker GatewayFilter 工厂使用 Spring Cloud CircuitBreaker API 将网关路由包装在断路器中。Spring Cloud CircuitBreaker 支持多个可与 Spring Cloud Gateway 一起使用的库。Spring Cloud 开箱即用地支持 Resilience4J。
要启用 Spring Cloud CircuitBreaker 过滤器,您需要放置spring-cloud-starter-circuitbreaker-reactor-resilience4j
在类路径中。以下示例配置 Spring Cloud CircuitBreaker GatewayFilter
:
示例 20.application.yml
spring:
cloud:
gateway:
routes:
- id: circuitbreaker_route
uri: https://example.org
filters:
- CircuitBreaker=myCircuitBreaker
要配置断路器,请参阅您正在使用的底层断路器实现的配置。
Spring Cloud CircuitBreaker 过滤器也可以接受一个可选fallbackUri
参数。目前,仅forward:
支持方案化 URI。如果调用了fallback,则将请求转发到URI匹配的控制器。以下示例配置了这样的回退:
示例 21.application.yml
spring:
cloud:
gateway:
routes:
- id: circuitbreaker_route
uri: lb://backing-service:8088
predicates:
- Path=/consumingServiceEndpoint
filters:
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/inCaseOfFailureUseThis
- RewritePath=/consumingServiceEndpoint, /backingServiceEndpoint
下面的清单在 Java 中做同样的事情:
例 22.Application.java
@Bean
public RouteLocator routes(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
此示例在调用断路器回退时转发到URI。请注意,此示例还演示了(可选)Spring Cloud LoadBalancer 负载平衡(由lb
目标 URI 上的前缀定义)。
主要场景是使用fallbackUri
定义网关应用程序中的内部控制器或处理程序。但是,您也可以将请求重新路由到外部应用程序中的控制器或处理程序,如下所示:
示例 23.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:9994
predicates:
- Path=/fallback
在此示例中,网关应用程序中没有fallback
端点或处理程序。但是,在另一个应用程序中有一个,在localhost:9994
.
在请求被转发到回退的情况下,Spring Cloud CircuitBreaker Gateway 过滤器还提供了Throwable
导致它的原因。它被添加到ServerWebExchange
作为ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR
在网关应用程序中处理回退时可以使用的属性。
对于外部控制器/处理程序场景,可以添加带有异常详细信息的标头。
在状态代码上使断路器回退
在某些情况下,您可能希望根据从其包裹的路由返回的状态代码来触发断路器。断路器配置对象采用状态代码列表,如果返回将导致断路器跳闸。在设置要使断路器跳闸的状态代码时,您可以使用带有状态代码值的整数或HttpStatus
枚举的字符串表示形式。
示例 24.application.yml
spring:
cloud:
gateway:
routes:
- id: circuitbreaker_route
uri: lb://backing-service:8088
predicates:
- Path=/consumingServiceEndpoint
filters:
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/inCaseOfFailureUseThis
statusCodes:
- 500
- "NOT_FOUND"
例 25.Application.java
@Bean
public RouteLocator routes(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();
}
FallbackHeaders
工厂允许您在转发到外部应用程序中FallbackHeaders
的请求的标头中添加 Spring Cloud CircuitBreaker 执行异常详细信息,如以下场景所示:fallbackUri
示例 26.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:9994
predicates:
- Path=/fallback
filters:
- name: FallbackHeaders
args:
executionExceptionTypeHeaderName: Test-Header
在此示例中,在运行断路器时发生执行异常后,请求将被转发到fallback
运行在 上的应用程序中的端点或处理程序localhost:9994
。具有异常类型、消息和(如果可用)根本原因异常类型和消息的标头由FallbackHeaders
过滤器添加到该请求。
您可以通过设置以下参数的值(显示为默认值)来覆盖配置中标头的名称:
-
executionExceptionTypeHeaderName
("Execution-Exception-Type"
) -
executionExceptionMessageHeaderName
("Execution-Exception-Message"
) -
rootCauseExceptionTypeHeaderName
("Root-Cause-Exception-Type"
) -
rootCauseExceptionMessageHeaderName
("Root-Cause-Exception-Message"
)
有关断路器和网关的更多信息,请参阅Spring Cloud CircuitBreaker Factory 部分。
MapRequestHeader
MapRequestHeader
GatewayFilter
工厂接受fromHeader
和toHeader
参数。它创建一个新的命名标头 ( ),并从传入的 http 请求中从toHeader
现有的命名标头 ( ) 中提取值。fromHeader
如果输入标头不存在,则过滤器没有影响。如果新的命名标头已经存在,则其值将使用新值进行扩充。以下示例配置了一个MapRequestHeader
:
示例 27.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
标头的更新值。
PrefixPath
工厂采用PrefixPath
GatewayFilter
单个prefix
参数。以下示例配置了一个PrefixPath
GatewayFilter
:
示例 28.application.yml
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- PrefixPath=/mypath
/mypath
这将作为所有匹配请求路径的前缀。因此,/hello
将向 发送请求/mypath/hello
。
PreserveHostHeader
PreserveHostHeader
GatewayFilter
工厂没有参数。此过滤器设置路由过滤器检查的请求属性,以确定是否应发送原始主机头,而不是由 HTTP 客户端确定的主机头。以下示例配置了一个PreserveHostHeader
GatewayFilter
:
示例 29.application.yml
spring:
cloud:
gateway:
routes:
- id: preserve_host_route
uri: https://example.org
filters:
- PreserveHostHeader
RequestRateLimiter
RequestRateLimiter
GatewayFilter
工厂使用实现RateLimiter
来确定是否允许当前请求继续。如果不是,HTTP 429 - Too Many Requests
则返回(默认情况下)状态。
此过滤器采用可选keyResolver
参数和特定于速率限制器的参数(本节稍后描述)。
keyResolver
是实现KeyResolver
接口的bean。在配置中,使用 SpEL 按名称引用 bean。 #{@myKeyResolver}
是一个引用名为 的 bean 的 SpEL 表达式myKeyResolver
。以下清单显示了该KeyResolver
界面:
示例 30.KeyResolver.java
public interface KeyResolver {
Mono<String> resolve(ServerWebExchange exchange);
}
该KeyResolver
接口让可插拔策略派生出限制请求的密钥。在未来的里程碑版本中,将会有一些KeyResolver
实现。
的默认实现KeyResolver
是PrincipalNameKeyResolver
,它Principal
从ServerWebExchange
和调用中检索Principal.getName()
。
默认情况下,如果KeyResolver
找不到密钥,则拒绝请求。spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key
您可以通过设置(true
或false
) 和spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code
属性来调整此行为。
Redis RateLimiter
Redis 的实现基于在Stripe完成的工作。它需要使用spring-boot-starter-data-redis-reactive
Spring Boot 启动器。
使用的算法是令牌桶算法。
该redis-rate-limiter.replenishRate
属性是您希望每秒允许用户执行多少请求,而不会丢弃任何请求。这是令牌桶被填充的速率。
该redis-rate-limiter.burstCapacity
属性是允许用户在一秒钟内执行的最大请求数。这是令牌桶可以容纳的令牌数量。将此值设置为零会阻止所有请求。
该redis-rate-limiter.requestedTokens
属性是请求花费多少令牌。这是每个请求从存储桶中获取的令牌数,默认为1
.
replenishRate
通过在和中设置相同的值来实现稳定的速率burstCapacity
。burstCapacity
通过设置高于可以允许临时突发replenishRate
。在这种情况下,需要允许速率限制器在突发之间有一段时间(根据replenishRate
),因为两个连续的突发将导致请求被丢弃(HTTP 429 - Too Many Requests
)。以下清单配置了一个redis-rate-limiter
:
下面的速率限制1 request/s
是通过设置replenishRate
所需的请求数、requestedTokens
以秒为单位的时间跨度以及 和burstCapacity
的乘积来实现的replenishRate
,requestedTokens
例如设置replenishRate=1
,requestedTokens=60
并将burstCapacity=60
导致 的限制1 request/min
。
示例 32.application.yml
spring:
cloud:
gateway:
routes:
- id: requestratelimiter_route
uri: https://example.org
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
redis-rate-limiter.requestedTokens: 1
以下示例在 Java 中配置 KeyResolver:
示例 33. Config.java
@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}
这定义了每个用户 10 的请求速率限制。允许 20 个突发,但是在下一秒,只有 10 个请求可用。这KeyResolver
是一个获取user
请求参数的简单方法(注意,不建议在生产环境中这样做)。
您还可以将速率限制器定义为实现RateLimiter
接口的 bean。在配置中,您可以使用 SpEL 按名称引用 bean。 #{@myRateLimiter}
是一个 SpEL 表达式,它引用了一个名为 的 bean myRateLimiter
。下面的清单定义了一个使用KeyResolver
前面清单中定义的速率限制器:
示例 34.application.yml
spring:
cloud:
gateway:
routes:
- id: requestratelimiter_route
uri: https://example.org
filters:
- name: RequestRateLimiter
args:
rate-limiter: "#{@myRateLimiter}"
key-resolver: "#{@userKeyResolver}"
RedirectTo
RedirectTo
GatewayFilter
工厂有两个参数,status
和url
。参数应为status
300 系列重定向 HTTP 代码,例如 301。url
参数应为有效 URL。这是Location
标头的值。对于相对重定向,您应该使用uri: no://op
路由定义的 uri。以下清单配置了一个RedirectTo
GatewayFilter
:
示例 35.application.yml
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- RedirectTo=302, https://acme.org
这将发送带有Location:https://acme.org
标头的状态 302 以执行重定向。
RemoveRequestHeader
RemoveRequestHeader
GatewayFilter
工厂接受一个name
参数。它是要删除的标头的名称。以下清单配置了一个RemoveRequestHeader
GatewayFilter
:
示例 36.application.yml
spring:
cloud:
gateway:
routes:
- id: removerequestheader_route
uri: https://example.org
filters:
- RemoveRequestHeader=X-Request-Foo
这会在将X-Request-Foo
标头发送到下游之前将其删除。
RemoveResponseHeader
RemoveResponseHeader
GatewayFilter
工厂接受一个name
参数。它是要删除的标头的名称。以下清单配置了一个RemoveResponseHeader
GatewayFilter
:
示例 37.application.yml
spring:
cloud:
gateway:
routes:
- id: removeresponseheader_route
uri: https://example.org
filters:
- RemoveResponseHeader=X-Response-Foo
这将X-Response-Foo
在返回给网关客户端之前从响应中删除标头。
要删除任何类型的敏感标头,您应该为您可能想要这样做的任何路由配置此过滤器。此外,您可以通过使用配置此过滤器一次spring.cloud.gateway.default-filters
并将其应用于所有路由。
RemoveRequestParameter
RemoveRequestParameter
GatewayFilter
工厂接受一个name
参数。它是要删除的查询参数的名称。以下示例配置了一个RemoveRequestParameter
GatewayFilter
:
示例 38.application.yml
spring:
cloud:
gateway:
routes:
- id: removerequestparameter_route
uri: https://example.org
filters:
- RemoveRequestParameter=red
这将在将red
参数发送到下游之前将其删除。
RewritePath
工厂接受一个RewritePath
GatewayFilter
路径regexp
参数和一个replacement
参数。这使用 Java 正则表达式以灵活的方式重写请求路径。以下清单配置了一个RewritePath
GatewayFilter
:
示例 39.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 规范,$
应将其替换为。$\
RewriteLocationResponseHeader
RewriteLocationResponseHeader
GatewayFilter
工厂修改响应头的值,Location
通常是为了摆脱后端特定的细节。它需要stripVersionMode
、locationHeaderName
、hostValue
和protocolsRegex
参数。以下清单配置了一个RewriteLocationResponseHeader
GatewayFilter
:
示例 40.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
则使用请求标头的值。
该protocolsRegex
参数必须是有效的正则表达式String
,协议名称与之匹配。如果不匹配,过滤器什么也不做。默认值为http|https|ftp|ftps
.
RewriteResponseHeader
RewriteResponseHeader
GatewayFilter
工厂采用、name
和regexp
参数replacement
。它使用 Java 正则表达式以灵活的方式重写响应标头值。以下示例配置了一个RewriteResponseHeader
GatewayFilter
:
示例 41.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
其设置为。由于 YAML 规范,/42?user=ford&password=***&flag=true
您必须使用$\
to 表示。$
SaveSession
工厂在将呼叫转发到下游之前SaveSession
GatewayFilter
强制执行WebSession::save
操作。这在使用诸如带有惰性数据存储的Spring Session 之类的东西时特别有用,并且您需要确保在进行转发调用之前已保存会话状态。以下示例配置了一个:SaveSession
GatewayFilter
示例 42.application.yml
spring:
cloud:
gateway:
routes:
- id: save_session
uri: https://example.org
predicates:
- Path=/foo/**
filters:
- SaveSession
如果您将Spring Security与 Spring Session 集成并希望确保安全详细信息已转发到远程进程,这很关键。
6.19。SecureHeaders
GatewayFilter
工厂_
根据这篇博SecureHeaders
GatewayFilter
文中的建议,工厂会在响应中添加一些标头。
添加了以下标题(显示为默认值):
-
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
使用逗号分隔值设置属性。以下示例显示了如何执行此操作:
spring.cloud.gateway.filter.secure-headers.disable=x-frame-options,strict-transport-security
6.20。SetPath
GatewayFilter
工厂_
SetPath
GatewayFilter
工厂采用路径参数template
。它通过允许路径的模板化段提供了一种操作请求路径的简单方法。这使用来自 Spring Framework 的 URI 模板。允许多个匹配段。以下示例配置了一个SetPath
GatewayFilter
:
示例 43.application.yml
spring:
cloud:
gateway:
routes:
- id: setpath_route
uri: https://example.org
predicates:
- Path=/red/{segment}
filters:
- SetPath=/{segment}
对于 的请求路径/red/blue
,这会将路径设置为/blue
在发出下游请求之前。
6.21。SetRequestHeader
GatewayFilter
工厂_
SetRequestHeader
GatewayFilter
工厂接受name
和value
参数。以下清单配置了一个SetRequestHeader
GatewayFilter
:
示例 44.application.yml
spring:
cloud:
gateway:
routes:
- id: setrequestheader_route
uri: https://example.org
filters:
- SetRequestHeader=X-Request-Red, Blue
这GatewayFilter
将替换(而不是添加)具有给定名称的所有标题。因此,如果下游服务器以 响应X-Request-Red:1234
,这将被替换X-Request-Red:Blue
为下游服务将接收的内容。
SetRequestHeader
知道用于匹配路径或主机的 URI 变量。URI 变量可以在值中使用并在运行时扩展。以下示例配置SetRequestHeader
GatewayFilter
使用变量的 an:
示例 45.application.yml
spring:
cloud:
gateway:
routes:
- id: setrequestheader_route
uri: https://example.org
predicates:
- Host: {segment}.myhost.org
filters:
- SetRequestHeader=foo, bar-{segment}
6.22。SetResponseHeader
GatewayFilter
工厂_
SetResponseHeader
GatewayFilter
工厂接受name
和value
参数。以下清单配置了一个SetResponseHeader
GatewayFilter
:
示例 46.application.yml
spring:
cloud:
gateway:
routes:
- id: setresponseheader_route
uri: https://example.org
filters:
- SetResponseHeader=X-Response-Red, Blue
此 GatewayFilter 用给定名称替换(而不是添加)所有标头。因此,如果下游服务器以 响应 ,则将其X-Response-Red:1234
替换为X-Response-Red:Blue
,这是网关客户端将收到的。
SetResponseHeader
知道用于匹配路径或主机的 URI 变量。URI 变量可以在值中使用,并将在运行时扩展。以下示例配置SetResponseHeader
GatewayFilter
使用变量的 an:
示例 47.application.yml
spring:
cloud:
gateway:
routes:
- id: setresponseheader_route
uri: https://example.org
predicates:
- Host: {segment}.myhost.org
filters:
- SetResponseHeader=foo, bar-{segment}
6.23。SetStatus
GatewayFilter
工厂_
工厂采用SetStatus
GatewayFilter
单个参数status
. 它必须是有效的 Spring HttpStatus
。它可以是整数值404
或枚举的字符串表示形式:NOT_FOUND
。以下清单配置了一个SetStatus
GatewayFilter
:
示例 48.application.yml
spring:
cloud:
gateway:
routes:
- id: setstatusstring_route
uri: https://example.org
filters:
- SetStatus=BAD_REQUEST
- id: setstatusint_route
uri: https://example.org
filters:
- SetStatus=401
无论哪种情况,响应的 HTTP 状态都设置为 401。
您可以将其配置为SetStatus
GatewayFilter
在响应的标头中从代理请求返回原始 HTTP 状态代码。如果配置了以下属性,则标头将添加到响应中:
示例 49.application.yml
spring:
cloud:
gateway:
set-status:
original-status-header-name: original-http-status
StripPrefix
StripPrefix
GatewayFilter
工厂采用一个参数,parts
. 该parts
参数指示在将请求发送到下游之前要从请求中剥离的路径中的部分数。以下清单配置了一个StripPrefix
GatewayFilter
:
示例 50.application.yml
spring:
cloud:
gateway:
routes:
- id: nameRoot
uri: https://nameservice
predicates:
- Path=/name/**
filters:
- StripPrefix=2
当通过网关向发出请求时/name/blue/red
,向 发出的请求nameservice
看起来像nameservice/red
。
重试GatewayFilter
Retry
GatewayFilter
工厂支持以下参数:
-
retries
:应该尝试的重试次数。 -
statuses
:应该重试的HTTP状态码,用 表示org.springframework.http.HttpStatus
。 -
methods
:应该重试的HTTP方法,用 表示org.springframework.http.HttpMethod
。 -
series
:要重试的一系列状态码,用 表示org.springframework.http.HttpStatus.Series
。 -
exceptions
:应重试的抛出异常列表。 -
backoff
:为重试配置的指数退避。重试在 的退避间隔后执行firstBackoff * (factor ^ n)
,其中n
是迭代。如果maxBackoff
已配置,则应用的最大退避限制为maxBackoff
. 如果basedOnPreviousValue
为真,则使用 计算退避prevBackoff * factor
。
Retry
如果启用,则为过滤器配置以下默认值:
-
retries
: 三倍 -
series
: 5XX 系列 -
methods
: 获取方法 -
exceptions
:IOException
和TimeoutException
-
backoff
: 禁用
以下清单配置了 Retry GatewayFilter
:
示例 51.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
methods: GET,POST
backoff:
firstBackoff: 10ms
maxBackoff: 50ms
factor: 2
basedOnPreviousValue: false
使用带有forward: 前缀 URL 的重试过滤器时,应仔细编写目标端点,以便在发生错误时不会执行任何可能导致将响应发送到客户端并提交的操作。例如,如果目标端点是带注释的控制器,则目标控制器方法不应返回ResponseEntity 错误状态代码。相反,它应该抛出Exception 或发出错误信号(例如,通过Mono.error(ex) 返回值),重试过滤器可以配置为通过重试来处理。 |
|
---|---|
将重试过滤器与任何带有正文的 HTTP 方法一起使用时,正文将被缓存,并且网关将受到内存限制。正文缓存在由 定义的请求属性中ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR 。对象的类型是 a org.springframework.core.io.buffer.DataBuffer 。 |
|
---|---|
可以使用单个status
and来添加简化的“快捷方式”表示法method
。
下面两个例子是等价的:
示例 52.application.yml
spring:
cloud:
gateway:
routes:
- id: retry_route
uri: https://example.org
filters:
- name: Retry
args:
retries: 3
statuses: INTERNAL_SERVER_ERROR
methods: GET
backoff:
firstBackoff: 10ms
maxBackoff: 50ms
factor: 2
basedOnPreviousValue: false
- id: retryshortcut_route
uri: https://example.org
filters:
- Retry=3,INTERNAL_SERVER_ERROR,GET,10ms,50ms,2,false
6.26。RequestSize
GatewayFilter
工厂_
当请求大小大于允许的限制时,RequestSize
GatewayFilter
工厂可以限制请求到达下游服务。过滤器接受一个maxSize
参数。类型,因此maxSize is a
DataSize值可以定义为一个数字,后跟一个可选的
DataUnit后缀,例如“KB”或“MB”。字节的默认值为“B”。它是以字节为单位定义的请求的允许大小限制。以下清单配置了一个
RequestSizeGatewayFilter`:
示例 53.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
工厂将响应状态设置为413 Payload Too Large
附加标头。errorMessage
以下示例显示了这样一个errorMessage
:
errorMessage` : `Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB
如果未在路由定义中作为过滤器参数提供,则默认请求大小设置为 5 MB。 | |
---|---|
6.27。SetRequestHostHeader
GatewayFilter
工厂_
在某些情况下,可能需要覆盖主机标头。在这种情况下,SetRequestHostHeader
GatewayFilter
工厂可以用指定的值替换现有的主机头。过滤器接受一个host
参数。以下清单配置了一个SetRequestHostHeader
GatewayFilter
:
示例 54.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
工厂将主机头的SetRequestHostHeader
GatewayFilter
值替换为example.org
.
6.28。修改请求体GatewayFilter
工厂
您可以使用ModifyRequestBody
过滤器过滤器在网关将请求主体发送到下游之前对其进行修改。
只能使用 Java DSL 配置此过滤器。 | |
---|---|
以下清单显示了如何修改请求正文GatewayFilter
:
@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;
}
}
如果请求没有正文,RewriteFilter 则将通过null 。Mono.empty() 应返回以在请求中分配缺少的正文。 |
|
---|---|
6.29。修改响应体GatewayFilter
工厂
您可以使用ModifyResponseBody
过滤器在将响应正文发送回客户端之前对其进行修改。
只能使用 Java DSL 配置此过滤器。 | |
---|---|
以下清单显示了如何修改响应正文GatewayFilter
:
@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();
}
如果响应没有正文,RewriteFilter 则将通过null 。Mono.empty() 应返回以在响应中分配缺少的正文。 |
|
---|---|
6.30。令牌中继GatewayFilter
工厂
令牌中继是 OAuth2 消费者充当客户端并将传入令牌转发给传出资源请求的地方。消费者可以是纯客户端(如 SSO 应用程序)或资源服务器。
Spring Cloud Gateway 可以将 OAuth2 访问令牌向下游转发到它所代理的服务。要将此功能添加到网关,您需要添加 TokenRelayGatewayFilterFactory
如下内容:
应用程序.java
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("resource", r -> r.path("/resource")
.filters(f -> f.tokenRelay())
.uri("http://localhost:9000"))
.build();
}
或这个
应用程序.yaml
spring:
cloud:
gateway:
routes:
- id: resource
uri: http://localhost:9000
predicates:
- Path=/resource
filters:
- TokenRelay=
并且它将(除了登录用户并获取令牌之外)将身份验证令牌传递给下游的服务(在这种情况下 /resource
)。
要为 Spring Cloud Gateway 启用此功能,请添加以下依赖项
org.springframework.boot:spring-boot-starter-oauth2-client
它是如何工作的?{githubmaster}/src/main/java/org/springframework/cloud/gateway/security/TokenRelayGatewayFilterFactory.java[filter] 从当前经过身份验证的用户中提取访问令牌,并将其放入下游请求的请求标头中。
有关完整的工作示例,请参阅此项目。
仅当设置了将触发创建beanTokenRelayGatewayFilterFactory 的适当属性时才会创建bean。 spring.security.oauth2.client.*``ReactiveClientRegistrationRepository
|
|
---|---|
ReactiveOAuth2AuthorizedClientService used by 的默认实现使用TokenRelayGatewayFilterFactory 内存数据存储。ReactiveOAuth2AuthorizedClientService 如果您需要更强大的解决方案, 您将需要提供自己的实现。 |
|
---|---|
6.31。CacheRequestBody
GatewayFilter
工厂_
有一定的情况需要读取body。由于请求体流只能读取一次,所以我们需要缓存请求体。您可以使用CacheRequestBody
过滤器在请求正文发送到下游之前缓存请求正文并从 exchagne 属性获取正文。
以下清单显示了如何缓存请求正文GatewayFilter
:
@Bean
public RouteLocator routes(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();
}
示例 55.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
将提取请求正文并将其转换为正文类(例如java.lang.String
,在前面的示例中定义)。然后将其放置在 中,ServerWebExchange.getAttributes()
并使用 中定义的键ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR
。
此过滤器仅适用于 http 请求(包括 https)。 | |
---|---|
6.32。默认过滤器
要添加过滤器并将其应用于所有路由,您可以使用spring.cloud.gateway.default-filters
. 此属性采用过滤器列表。以下清单定义了一组默认过滤器:
示例 56.application.yml
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Red, Default-Blue
- PrefixPath=/httpbin
全局过滤器
该GlobalFilter
接口具有与 相同的签名GatewayFilter
。这些是有条件地应用于所有路由的特殊过滤器。
组合全局过滤器和GatewayFilter
排序
当请求与路由匹配时,过滤 Web 处理程序会将 的所有实例GlobalFilter
和所有特定于路由的实例添加GatewayFilter
到过滤器链中。这个组合的过滤器链是按org.springframework.core.Ordered
接口排序的,你可以通过实现getOrder()
方法来设置。
由于 Spring Cloud Gateway 区分过滤器逻辑执行的“前”和“后”阶段(请参阅它的工作原理),具有最高优先级的过滤器是“前”阶段的第一个和“后”阶段的最后一个 -阶段。
以下清单配置了一个过滤器链:
例 57.ExampleConfiguration.java
@Bean
public GlobalFilter customFilter() {
return new CustomGlobalFilter();
}
public class CustomGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("custom global filter");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1;
}
}
转发路由过滤器
在ForwardRoutingFilter
exchange 属性中查找 URI ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
。如果 URL 有一个forward
方案(例如forward:///localendpoint
),它使用 SpringDispatcherHandler
来处理请求。请求 URL 的路径部分被转发 URL 中的路径覆盖。未修改的原始 URL 将附加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR
属性中的列表中。
ReactiveLoadBalancerClientFilter
在ReactiveLoadBalancerClientFilter
名为 的交换属性中查找 URI ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
。如果 URL 有一个lb
方案(例如lb://myservice
),它使用 Spring CloudReactorLoadBalancer
将名称(在本例中)解析为myservice
实际的主机和端口,并替换同一属性中的 URI。未修改的原始 URL 将附加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR
属性中的列表中。过滤器还查看ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR
属性以查看它是否等于lb
。如果是这样,则适用相同的规则。以下清单配置了一个ReactiveLoadBalancerClientFilter
:
示例 58.application.yml
spring:
cloud:
gateway:
routes:
- id: myRoute
uri: lb://service
predicates:
- Path=/service/**
Netty 路由过滤器
如果位于ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
交换属性中的 URL 具有http
orhttps
方案,则 Netty 路由过滤器运行。它使用 NettyHttpClient
发出下游代理请求。响应被放入ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR
交换属性中,以供稍后的过滤器使用。(还有一个WebClientHttpRoutingFilter
执行相同功能但不需要 Netty 的实验。)
Netty 写响应过滤器
如果交换属性中NettyWriteResponseFilter
有 Netty HttpClientResponse
,则运行。ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR
它在所有其他过滤器完成后运行,并将代理响应写回网关客户端响应。(还有一个WebClientWriteResponseFilter
执行相同功能但不需要 Netty 的实验。)
RouteToRequestUrl
如果交换属性中有Route
对象,则运行。它基于请求 URI 创建一个新的 URI,但使用对象的 URI 属性进行更新。新的 URI 被放置在exchange 属性中。ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR``RouteToRequestUrlFilter``Route``ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
如果 URI 具有方案前缀,例如lb:ws://serviceid
,lb
则从 URI 中剥离方案并放置在ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR
过滤器链中以供稍后使用。
Websocket 路由过滤器
如果位于ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
exchange 属性中的 URL 具有ws
orwss
方案,则 websocket 路由过滤器运行。它使用 Spring WebSocket 基础设施向下游转发 websocket 请求。
您可以通过在 URI 前加上前缀来负载平衡 websocket lb
,例如lb:ws://serviceid
.
如果你使用SockJS作为普通 HTTP 的后备,你应该配置一个普通的 HTTP 路由以及 websocket 路由。
以下清单配置了一个 websocket 路由过滤器:
示例 59.application.yml
spring:
cloud:
gateway:
routes:
# SockJS route
- id: websocket_sockjs_route
uri: http://localhost:3001
predicates:
- Path=/websocket/info/**
# Normal Websocket route
- id: websocket_route
uri: ws://localhost:3001
predicates:
- Path=/websocket/**
网关指标过滤器
要启用网关指标,请将 spring-boot-starter-actuator 添加为项目依赖项。然后,默认情况下,只要该属性spring.cloud.gateway.metrics.enabled
未设置为,网关指标过滤器就会运行false
。spring.cloud.gateway.requests
此过滤器添加一个使用以下标签命名的计时器指标:
-
routeId
: 路由ID。 -
routeUri
:API 路由到的 URI。 -
outcome
:结果,按HttpStatus.Series分类。 -
status
:返回给客户端的请求的HTTP状态。 -
httpStatusCode
:返回给客户端的请求的 HTTP 状态。 -
httpMethod
:用于请求的 HTTP 方法。
此外,通过该属性spring.cloud.gateway.metrics.tags.path.enabled
(默认设置为 false),您可以使用标签激活额外的指标:
-
path
:请求的路径。
然后可以从这些指标中提取/actuator/metrics/spring.cloud.gateway.requests
并轻松与 Prometheus 集成以创建Grafana 仪表板。
要启用 prometheus 端点,请添加micrometer-registry-prometheus
为项目依赖项。
将交换标记为已路由
网关路由 a 后,它通过添加 交换属性将该交换ServerWebExchange
标记为“已路由” 。gatewayAlreadyRouted
一旦请求被标记为已路由,其他路由过滤器将不会再次路由该请求,实质上是跳过过滤器。您可以使用一些便捷的方法将交换标记为已路由或检查交换是否已被路由。
-
ServerWebExchangeUtils.isAlreadyRouted
获取一个ServerWebExchange
对象并检查它是否已被“路由”。 -
ServerWebExchangeUtils.setAlreadyRouted
获取一个ServerWebExchange
对象并将其标记为“已路由”。
HttpHeadersFilters
HttpHeadersFilters 在将请求发送到下游之前应用于请求,例如在NettyRoutingFilter
.
转发标头过滤器
标Forwarded
头过滤器创建一个Forwarded
标头以发送到下游服务。它将Host
当前请求的标头、方案和端口添加到任何现有Forwarded
标头。
RemoveHopByHop 标头过滤器
标RemoveHopByHop
头过滤器从转发的请求中删除标头。删除的默认标头列表来自IETF。
默认删除的标题是:
- 联系
- 活着
- 代理验证
- 代理授权
- TE
- 预告片
- 传输编码
- 升级
要更改此设置,请将spring.cloud.gateway.filter.remove-hop-by-hop.headers
属性设置为要删除的标头名称列表。
XForwarded 标头过滤器
标XForwarded
头过滤器创建各种X-Forwarded-*
标头以发送到下游服务。它使用Host
当前请求的标头、方案、端口和路径来创建各种标头。
可以通过以下布尔属性控制单个标题的创建(默认为 true):
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
TLS 和 SSL
网关可以通过遵循通常的 Spring 服务器配置来监听 HTTPS 上的请求。以下示例显示了如何执行此操作:
例 60.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 后端,则可以使用以下配置将网关配置为信任所有下游证书:
示例 61.application.yml
spring:
cloud:
gateway:
httpclient:
ssl:
useInsecureTrustManager: true
使用不安全的信任管理器不适合生产。对于生产部署,您可以使用一组已知证书配置网关,它可以使用以下配置信任这些证书:
示例 62.application.yml
spring:
cloud:
gateway:
httpclient:
ssl:
trustedX509Certificates:
- cert1.pem
- cert2.pem
如果 Spring Cloud Gateway 没有配置受信任的证书,则使用默认的信任存储(您可以通过设置javax.net.ssl.trustStore
系统属性来覆盖它)。
TLS 握手
网关维护一个客户端池,用于路由到后端。通过 HTTPS 进行通信时,客户端会启动 TLS 握手。许多超时与此握手相关。您可以配置这些超时,可以按如下方式配置(显示默认值):
示例 63.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
接口的定义:
示例 64.RouteDefinitionLocator.java
public interface RouteDefinitionLocator {
Flux<RouteDefinition> getRouteDefinitions();
}
默认情况下,PropertiesRouteDefinitionLocator
使用 Spring Boot 的@ConfigurationProperties
机制加载属性。
早期的配置示例都使用使用位置参数而不是命名参数的快捷表示法。下面两个例子是等价的:
示例 65.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
对于网关的某些用途,属性就足够了,但某些生产用例受益于从外部源(例如数据库)加载配置。未来的里程碑版本将具有RouteDefinitionLocator
基于 Spring Data Repositories 的实现,例如 Redis、MongoDB 和 Cassandra。
RouteDefinition 指标
要启用RouteDefinition
指标,请将 spring-boot-starter-actuator 添加为项目依赖项。然后,默认情况下,只要该属性spring.cloud.gateway.metrics.enabled
设置为,这些指标就可用true
。将添加一个名为的量规度量spring.cloud.gateway.routes.count
,其值为RouteDefinitions
. 该指标可从/actuator/metrics/spring.cloud.gateway.routes.count
.
路由元数据配置
您可以使用元数据为每个路由配置附加参数,如下所示:
示例 66.application.yml
spring:
cloud:
gateway:
routes:
- id: route_with_metadata
uri: https://example.org
metadata:
optionName: "OptionValue"
compositeObject:
name: "value"
iAmNumber: 1
您可以从交换中获取所有元数据属性,如下所示:
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
// get all metadata properties
route.getMetadata();
// get a single metadata property
route.getMetadata(someKey);
Http超时配置
可以为所有路由配置 Http 超时(响应和连接),并为每个特定路由覆盖。
全局超时
要配置全局 http 超时:connect-timeout
必须以毫秒为单位指定。response-timeout
必须指定为 java.time.Duration
全局 http 超时示例
spring:
cloud:
gateway:
httpclient:
connect-timeout: 1000
response-timeout: 5s
每条路由超时
要配置每条路由超时:connect-timeout
必须以毫秒为单位指定。response-timeout
必须以毫秒为单位指定。
通过配置进行每条路由 http 超时配置
- id: per_route_timeouts
uri: https://example.org
predicates:
- name: Path
args:
pattern: /delay/{timeout}
metadata:
response-timeout: 200
connect-timeout: 200
使用 Java DSL 的每条路由超时配置
import static org.springframework.cloud.gateway.support.RouteMetadataUtils.CONNECT_TIMEOUT_ATTR;
import static org.springframework.cloud.gateway.support.RouteMetadataUtils.RESPONSE_TIMEOUT_ATTR;
@Bean
public RouteLocator customRouteLocator(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();
}
response-timeout
具有负值的 per-route将禁用全局response-timeout
值。
- id:per_route_timeouts
网址:https://example.org
谓词:
- 名称:路径
参数:
模式:/延迟/{超时}
元数据:
响应超时:-1
流畅的 Java 路由 API
为了允许在 Java 中进行简单配置,RouteLocatorBuilder
bean 包含一个流式 API。下面的清单显示了它是如何工作的:
例 67.GatewaySampleApplication.java
// static imports from GatewayFilters and RoutePredicates
@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")
.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();
}
这种风格还允许更多的自定义谓词断言。bean定义的谓词RouteDefinitionLocator
使用逻辑组合and
。通过使用 fluent Java API,您可以在类上使用and()
、or()
和negate()
运算符Predicate
。
路线DiscoveryClient
定义定位器
您可以将网关配置为基于在DiscoveryClient
兼容服务注册表中注册的服务创建路由。
要启用此功能,请设置spring.cloud.gateway.discovery.locator.enabled=true
并确保DiscoveryClient
实现(例如 Netflix Eureka、Consul 或 Zookeeper)在类路径上并启用。
DiscoveryClient
为路由配置谓词和过滤器
默认情况下,网关为使用DiscoveryClient
.
默认谓词是使用模式定义的路径谓词/serviceId/**
,其中serviceId
是来自DiscoveryClient
.
默认过滤器是带有正则表达式/serviceId/?(?<remaining>.*)
和替换的重写路径过滤器/${remaining}
。这会在请求被发送到下游之前从路径中去除服务 ID。
如果要自定义DiscoveryClient
路由使用的谓词或过滤器,请设置spring.cloud.gateway.discovery.locator.predicates[x]
和spring.cloud.gateway.discovery.locator.filters[y]
。这样做时,如果要保留该功能,则需要确保包含前面显示的默认谓词和过滤器。以下示例显示了它的样子:
示例 68.application.properties
spring.cloud.gateway.discovery.locator.predicates[0].name:路径
spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]: "'/'+serviceId+'/**'"
spring.cloud.gateway.discovery.locator.predicates[1].name:主机
spring.cloud.gateway.discovery.locator.predicates[1].args[pattern]: "'**.foo.com'"
spring.cloud.gateway.discovery.locator.filters[0].name:断路器
spring.cloud.gateway.discovery.locator.filters[0].args[name]: serviceId
spring.cloud.gateway.discovery.locator.filters[1].name:重写路径
spring.cloud.gateway.discovery.locator.filters[1].args[regexp]: "'/' + serviceId + '/?(?<remaining>.*)'"
spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'"
Reactor Netty 访问日志eference/html/#reactor-netty-access-logs)
要启用 Reactor Netty 访问日志,请设置-Dreactor.netty.http.server.accessLogEnabled=true
.
您可以将日志记录系统配置为具有单独的访问日志文件。以下示例创建一个 Logback 配置:
例 69.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 行为。“全局” CORS 配置是 URL 模式到Spring FrameworkCorsConfiguration
的映射。以下示例配置 CORS:
例 70.application.yml
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "https://docs.spring.io"
allowedMethods:
- GET
在前面的示例中,允许来自docs.spring.io
所有 GET 请求路径的请求的 CORS 请求。
要为某些网关路由谓词未处理的请求提供相同的 CORS 配置,请将spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping
属性设置为true
. 当您尝试支持 CORS 预检请求并且您的路由谓词未评估为时,true
这很有用,因为 HTTP 方法是options
.
监控器 API
该/gateway
驱动器的端点,您可以监视和Spring的云网关应用程序进行交互。要远程访问,必须在应用程序属性中启用并通过 HTTP 或 JMX 公开端点。以下清单显示了如何执行此操作:
示例 71.application.properties
management.endpoint.gateway.enabled=true # default value
management.endpoints.web.exposure.include=gateway
15.1. 详细执行器格式
Spring Cloud Gateway 中添加了一种新的、更详细的格式。它为每个路由添加了更多详细信息,让您可以查看与每个路由关联的谓词和过滤器以及任何可用配置。以下示例配置/actuator/gateway/routes
:
[
{
"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
}
]
默认情况下启用此功能。要禁用它,请设置以下属性:
示例 72.application.properties
spring.cloud.gateway.actuator.verbose.enabled=false
这将true
在未来的版本中默认使用。
15.2. 检索路由过滤器
本节详细介绍如何检索路由过滤器,包括:
15.2.1. 全局过滤器
要检索应用于所有路由的全局过滤器GET
,请向/actuator/gateway/globalfilters
. 生成的响应类似于以下内容:
{
“org.spring framework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@77856cc5 ”:10100,
“o rg.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@4f6fd101 ”:10000,
“或g.springframework.cloud.gateway.filter.NettyWriteResponseFilter@32d22650 ”:-1,
" org.springframework.cloud.gateway.filter.ForwardRoutingFilter@10 6459d9": 2147483647,
“ org.springframework.cloud.gateway.filter.NettyRoutingFilter@1fbd 5e0”:2147483647,
" org.springframework.cloud.gateway.filter.ForwardPathFilter@33a71 d23": 0,
“org.s pringframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@135064ea ”:2147483637,
“ org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@23c05889 ”:2147483646
}
响应包含已到位的全局过滤器的详细信息。对于每个全局过滤器,都有过滤器对象的字符串表示形式(例如,org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@77856cc5
)和过滤器链中的相应顺序。}
15.2.2. 路由过滤器
要检索应用于路由的GatewayFilter
工厂,GET
请向/actuator/gateway/routefilters
. 生成的响应类似于以下内容:
{
“[ AddRequestHeaderGatewayFilterFactory@570ed9c configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]”:空,
“[ SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]”:空,
“[ SaveSessionGatewayFilterFactory@4449b273 configClass = Object]”:空
}
响应包含GatewayFilter
应用于任何特定路由的工厂的详细信息。对于每个工厂,都有对应对象的字符串表示形式(例如,[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]
)。请注意,该null
值是由于端点控制器的实现不完整,因为它试图设置对象在过滤器链中的顺序,这不适用于GatewayFilter
工厂对象。
15.3. 刷新路由缓存
要清除路由缓存,POST
请向/actuator/gateway/refresh
. 该请求返回没有响应正文的 200。
15.4. 检索网关中定义的路由
要检索网关中定义的路由,GET
请向/actuator/gateway/routes
. 生成的响应类似于以下内容:
[{
"route_id": "first_route",
“路由对象”:{
“断言”: “org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory $$ LAMBDA $ 432/ 1736826640 @ 1e9d7e7d ”
“过滤器”:[
“OrderedGatewayFilter {代表= org.springframework.cloud.gateway.filter.factory.PreserveHostHeaderGatewayFilterFactory $$ LAMBDA $ 436/ 674480275 @ 6631ef72 ,为了= 0}”
]
},
“订单”:0
},
{
"route_id": "second_route",
“路由对象”:{“谓词
”:“org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@cd8d298 ”,
“过滤器”:[]
},
“订单”:0
}]
响应包含网关中定义的所有路由的详细信息。下表描述了响应的每个元素(每个元素都是一个路由)的结构:
小路 | 类型 | 描述 |
---|---|---|
route_id |
细绳 | 路线标识。 |
route_object.predicate |
目的 | 路由谓词。 |
route_object.filters |
大批 |
GatewayFilter 工厂申请了这条路线。 |
order |
数字 | 路线顺序。 |
15.5。检索有关特定路线的信息
要检索有关单个路由的信息,GET
请向/actuator/gateway/routes/{id}
(例如,/actuator/gateway/routes/first_route
)发出请求。生成的响应类似于以下内容:
{
"id": "first_route",
“谓词”:[{
“名称”:“路径”,
"args": {"_genkey_0":"/first"}
}],
“过滤器”:[],
"uri": "https://www.uri-destination.org",
“订单”:0
}
下表描述了响应的结构:
小路 | 类型 | 描述 |
---|---|---|
id |
细绳 | 路线标识。 |
predicates |
大批 | 路由谓词的集合。每个项目定义给定谓词的名称和参数。 |
filters |
大批 | 应用于路由的过滤器集合。 |
uri |
细绳 | 路由的目标 URI。 |
order |
数字 | 路线顺序。 |
15.6。创建和删除特定路线
要创建路由,请使用指定路由字段的 JSON 正文POST
发出请求(请参阅检索有关特定路由的信息)。/gateway/routes/{id_route_to_create}
要删除路线,DELETE
请向/gateway/routes/{id_route_to_delete}
.
15.7. 回顾:所有端点的列表
下表总结了 Spring Cloud Gateway 执行器端点(请注意,每个端点都有/actuator/gateway
作为基本路径):
ID | HTTP 方法 | 描述 |
---|---|---|
globalfilters |
得到 | 显示应用于路由的全局过滤器列表。 |
routefilters |
得到 | 显示GatewayFilter 应用于特定路线的工厂列表。 |
refresh |
邮政 | 清除路由缓存。 |
routes |
得到 | 显示网关中定义的路由列表。 |
routes/{id} |
得到 | 显示有关特定路线的信息。 |
routes/{id} |
邮政 | 向网关添加新路由。 |
routes/{id} |
删除 | 从网关中删除现有路由。 |
15.8. 在多个网关实例之间共享路由
Spring Cloud Gateway 提供了两种RouteDefinitionRepository
实现。第一个是 InMemoryRouteDefinitionRepository
只存在于一个网关实例的内存中。这种类型的存储库不适合跨多个网关实例填充路由。
为了在 Spring Cloud Gateway 实例的集群*享路由,RedisRouteDefinitionRepository
可以使用。要启用这种存储库,必须将以下属性设置为 true:spring.cloud.gateway.redis-route-definition-repository.enabled
与 RedisRateLimiter Filter Factory 类似,它需要使用 spring-boot-starter-data-redis-reactive Spring Boot 启动器。
故障排除
本节介绍使用 Spring Cloud Gateway 时可能出现的常见问题。
16.1. 日志级别
以下记录器可能在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. 窃听
Reactor NettyHttpClient
可以HttpServer
启用窃听。与将reactor.netty
日志级别设置为DEBUG
或结合使用时TRACE
,它可以记录信息,例如通过网络发送和接收的标头和正文。要启用窃听,请分别为和设置spring.cloud.gateway.httpserver.wiretap=true
或。spring.cloud.gateway.httpclient.wiretap=true``HttpServer``HttpClient
开发者指南
这些是编写网关的一些自定义组件的基本指南。
17.1. 编写自定义路由谓词工厂
为了编写路由谓词,您需要将其实现RoutePredicateFactory
为 bean。有一个AbstractRoutePredicateFactory
可以扩展的抽象类。
MyRoutePredicateFactory.java
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {
public MyRoutePredicateFactory() {
super(Config.class);
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
// grab configuration from Config object
return exchange -> {
//grab the request
ServerHttpRequest request = exchange.getRequest();
//take information from the request to see if it
//matches configuration.
return matches(config, request);
};
}
public static class Config {
//Put the configuration properties for your filter here
}
}
17.2. 编写自定义 GatewayFilter 工厂
要编写GatewayFilter
,您必须将其实现GatewayFilterFactory
为 bean。您可以扩展一个名为AbstractGatewayFilterFactory
. 以下示例显示了如何执行此操作:
示例 73. PreGatewayFilterFactory.java
@Component
public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> {
public PreGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
// grab configuration from Config object
return (exchange, chain) -> {
//If you want to build a "pre" filter you need to manipulate the
//request before calling chain.filter
ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
//use builder to manipulate the request
return chain.filter(exchange.mutate().request(builder.build()).build());
};
}
public static class Config {
//Put the configuration properties for your filter here
}
}
PostGatewayFilterFactory.java
@Component
public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> {
public PostGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
// grab configuration from Config object
return (exchange, chain) -> {
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
ServerHttpResponse response = exchange.getResponse();
//Manipulate the response in some way
}));
};
}
public static class Config {
//Put the configuration properties for your filter here
}
}
17.2.1. 在配置中命名自定义过滤器和引用
自定义过滤器类名应以GatewayFilterFactory
.
例如,要引用Something
配置文件中命名的过滤器,该过滤器必须位于名为SomethingGatewayFilterFactory
.
可以创建一个不带 GatewayFilterFactory 后缀的网关过滤器,例如class AnotherThing . 此过滤器可以AnotherThing 在配置文件中引用。这不是受支持的命名约定,并且在将来的版本中可能会删除此语法。请更新过滤器名称以使其符合要求。 |
|
---|---|
17.3. 编写自定义全局过滤器
要编写自定义全局过滤器,您必须GlobalFilter
将接口实现为 bean。这会将过滤器应用于所有请求。
以下示例分别显示了如何设置全局前置和后置过滤器:
@Bean
public GlobalFilter customGlobalFilter() {
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);
}
@Bean
public GlobalFilter customGlobalPostFilter() {
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();
}