# Spring Cloud 网关
3.1.1
该项目提供了一个构建在 Spring 生态系统之上的 API 网关,包括: Spring 5、 Spring Boot2 和 Project Reactor。 Spring Cloud Gateway 旨在提供一种简单但有效的方法来路由到 API,并向它们提供跨领域的关注,例如:安全性、监视/度量和弹性。
# 1. How to Include Spring Cloud Gateway
要在项目中包含 Spring Cloud网关,请使用组 ID 为org.springframework.cloud
和工件 ID 为spring-cloud-starter-gateway
的 starter。请参阅Spring Cloud Project page (opens new window),以获取有关使用当前 Spring Cloud发布系列设置构建系统的详细信息。
如果包含启动器,但不希望启用网关,请设置spring.cloud.gateway.enabled=false
。
Spring Cloud网关是建立在Spring Boot 2.x (opens new window),Spring WebFlux (opens new window),和项目反应堆 (opens new window)之上的。因此,当你使用 Spring Cloud网关时,许多你熟悉的同步库(例如 Spring 数据和 Spring 安全性)和模式可能不适用,如果你不熟悉这些项目,我们建议你在使用 Spring Cloud Gateway 之前,先阅读他们的文档,以熟悉一些新概念。 |
---|
Spring Cloud网关需要由 Spring 启动和 Spring WebFlux 提供的 Netty 运行时。它在传统 Servlet 容器中或构建为 WAR 时不工作。 |
---|
# 2.词汇表
路线:网关的基本构建块。它由一个 ID、一个目标 URI、一组谓词和一组筛选器定义。如果聚合谓词为 true,则匹配路由。
谓词:这是Java8 函数谓词 (opens new window)。输入类型是一个[ Spring Framework
ServerWebExchange
](https://DOCS. Spring.io/ Spring/DOCS/5.0.x/javadoc-api/org/springframework/web/server/serverwebexchange.html)。这使你能够匹配 HTTP 请求中的任何内容,例如标题或参数。过滤器:这些是[
GatewayFilter
](https://github.com/ Spring-cloud/ Spring-cloud-gateway/tree/main/ Spring-cloud-gateway-server-server/SRC/main/main/java/org/springframework/cloud/gateway/filter/geter/getter/gatewayfilter.java)的实例在这里,你可以在发送下游请求之前或之后修改请求和响应。
# 3.它是如何工作的
下图提供了 Spring Cloud网关如何工作的高级概述:
客户端向 Spring Cloud网关提出请求。如果网关处理程序映射确定请求与路由匹配,则将请求发送到网关 Web 处理程序。此处理程序通过特定于该请求的筛选链来运行该请求。用虚线划分过滤器的原因是,过滤器可以在发送代理请求之前和之后运行逻辑。所有的“pre”过滤逻辑都会被执行。然后提出代理请求。在提出代理请求之后,将运行“POST”过滤逻辑。
在没有端口的路由中定义的 URI 分别获得 HTTP 和 HTTPS URI 的默认端口号 80 和 443. |
---|
# 4.配置路由谓词工厂和网关过滤器工厂
配置谓词和过滤器有两种方法:快捷方式和完全展开的参数。下面的大多数示例都使用了快捷方式。
名称和参数名称将以code
的形式在每个部分的第一个或两个表示中列出。参数通常按快捷方式配置所需的顺序列出。
# 4.1.快捷方式配置
快捷方式配置由筛选器名称识别,后面跟着一个等号(=
),后面是用逗号分隔的参数值(,
)。
应用程序.yml
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- Cookie=mycookie,mycookievalue
上一个示例用两个参数定义了Cookie
路由谓词工厂,cookie 名mycookie
和要匹配mycookievalue
的值。
# 4.2.完全展开的论证
完全展开的参数看起来更像是带有名称/值对的标准 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
谓词的快捷配置的完整配置。
# 5.路线谓词工厂
Spring Cloud网关将路由匹配为 Spring WebFluxHandlerMapping
基础设施的一部分。 Spring Cloud网关包括许多内置的路由谓词工厂。所有这些谓词在 HTTP 请求的不同属性上匹配。你可以将多个路由谓词工厂与逻辑and
语句组合在一起。
# 5.1.后路由谓词工厂
After
路由谓词工厂接受一个参数,adatetime
(这是一个 JavaZonedDateTime
)。此谓词匹配在指定的 DateTime 之后发生的请求。下面的示例配置一个 after 路由谓词:
示例 1.应用程序.yml
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
这条路线符合任何请求后提出的 JAN20,2017 年 17:42 山区时间(丹佛)。
# 5.2.前路由谓词工厂
Before
路由谓词工厂接受一个参数,adatetime
(这是一个 JavaZonedDateTime
)。此谓词匹配在指定的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]
这条路线符合任何在 JAN20,2017 年 17:42 山区时间(丹佛)之前提出的请求。
# 5.3.路由谓词之间的工厂
Between
路由谓词工厂接受两个参数,datetime1
和datetime2
,它们是 JavaZonedDateTime
对象。此谓词匹配发生在datetime1
之后和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]
这条路线符合在 JAN20,2017 年 17:42 山区时间(丹佛)之后和 JAN21,2017 年 17:42 山区时间(丹佛)之前提出的任何请求。这对于维护窗口可能是有用的。
# 5.4.cookie 路由谓词工厂
Cookie
路由谓词工厂接受两个参数,cookiename
和regexp
(这是一个 Java 正则表达式)。此谓词匹配具有给定名称且其值与正则表达式匹配的 cookie。下面的示例配置了一个 Cookie 路由谓词工厂:
示例 4.application.yml
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p
此路由匹配具有名为chocolate
的 cookie 的请求,其值与ch.p
正则表达式匹配。
# 5.5.头路由谓词工厂
Header
路由谓词工厂接受两个参数,header
和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+
正则表达式匹配(即它有一个或多个数字的值),则此路由匹配。
# 5.6.主机路由谓词工厂
Host
路由谓词工厂接受一个参数:主机名列表patterns
。该模式是一种 Ant 样式的模式,以.
作为分隔符。此谓词匹配与模式匹配的Host
头。下面的示例配置了一个主机路由谓词:
示例 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
,则此路由匹配。
这个谓词提取 URI 模板变量(例如sub
,在前面的示例中定义)作为名称和值的映射,并将其放在ServerWebExchange.getAttributes()
中,并在ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE
中定义一个键。然后这些值可供[GatewayFilter
工厂使用](#gateway-route-filters)
# 5.7.路由谓词工厂的方法
Method
路由谓词工厂接受一个methods
参数,该参数是一个或多个参数:要匹配的 HTTP 方法。下面的示例配置了一个方法路由谓词:
示例 7.application.yml
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST
如果请求方法是GET
或POST
,则此路由匹配。
# 5.8.路径谓词工厂
Path
路由谓词工厂接受两个参数: 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
或/red/1/
或/red/blue
或/blue/green
,则此路由匹配。
如果matchTrailingSlash
被设置为false
,那么请求路径/red/1/
将不会被匹配。
这个谓词提取 URI 模板变量(例如segment
,在前面的示例中定义)作为名称和值的映射,并将其放在ServerWebExchange.getAttributes()
中,并在ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE
中定义一个键。然后这些值可供[GatewayFilter
工厂]使用(#gateway-route-filters)
可以使用一种实用方法(称为get
)来使对这些变量的访问更容易。下面的示例展示了如何使用get
方法:
Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);
String segment = uriVariables.get("segment");
# 5.9.查询路由谓词工厂
Query
路由谓词工厂接受两个参数:一个必需的param
和一个可选的regexp
(这是一个 Java 正则表达式)。下面的示例配置一个查询路由谓词:
示例 9.application.yml
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=green
如果请求包含green
查询参数,则前面的路由匹配。
application.yml
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=red, gree.
如果请求包含一个red
查询参数,其值与gree.
regexp 匹配,则前面的路由匹配,因此green
和greet
将匹配。
# 5.10.RemoteAddr 路由谓词工厂
RemoteAddr
路由谓词工厂接受一个sources
的列表(最小大小为 1),这些字符串是 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
,则此路由匹配。
# 5.10.1.修改远程地址的解析方式
默认情况下,RemoteAddr 路由谓词工厂使用来自传入请求的远程地址。如果 Spring Cloud网关位于代理层的后面,这可能与实际的客户端 IP 地址不匹配。
你可以通过设置自定义RemoteAddressResolver
来定制远程地址的解析方式。 Spring Cloud网关带有一个基于X-forward-for 标头 (opens new window),XForwardedRemoteAddressResolver
的非默认远程地址解析器。
XForwardedRemoteAddressResolver
有两种静态构造函数方法,它们采用不同的方法实现安全性:
XForwardedRemoteAddressResolver::trustAll
返回一个RemoteAddressResolver
,它总是使用在X-Forwarded-For
头中找到的第一个 IP 地址。这种方法容易受到欺骗,因为恶意客户端可能会为X-Forwarded-For
设置初始值,该初始值将被解析器接受。XForwardedRemoteAddressResolver::maxTrustedIndex
获取一个索引,该索引与在 Spring Cloud网关前运行的受信任基础设施的数量相关。 Spring 如果云网关例如只能通过 HAProxy 访问,那么应该使用 1 的值。如果在 Spring Cloud网关可访问之前需要两个值得信赖的基础设施跳,那么应该使用 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")
)
# 5.11.权重路径谓词工厂
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 (opens new window),并将 20% 的流量转发给weighlow.org (opens new window)。
# 5.12.XForwarded 远程 addr 路由谓词工厂
XForwarded Remote Addr
路由谓词工厂接受一个sources
的列表(最小大小为 1),这些字符串是 CIDR 表示法(IPv4 或 IPv6)字符串,例如192.168.0.1/16
(其中192.168.0.1
是一个 IP 地址,16
是一个子网掩码)。
此路由谓词允许基于X-Forwarded-For
HTTP 报头对请求进行过滤。
这可以用于反向代理,例如负载均衡器或 Web 应用程序防火墙,在这些代理中,只有当请求来自由这些反向代理使用的受信任的 IP 地址列表时,才允许请求。
下面的示例配置了一个 XForWardeDremoteaddr 路由谓词:
示例 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网关包括许多内置的网关过滤工厂。
有关如何使用以下任何过滤器的更详细示例,请查看unit tests (opens new window)。 |
---|
# 6.1.AddRequestHeader``GatewayFilter
工厂
AddRequestHeader``GatewayFilter
工厂接受一个name
和value
参数。以下示例配置AddRequestHeader``GatewayFilter
:
示例 14.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
:
示例 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
工厂
AddRequestParameter``GatewayFilter
工厂接受一个name
和value
参数。以下示例配置AddRequestParameter``GatewayFilter
:
示例 16.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
:
示例 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
工厂
AddResponseHeader``GatewayFilter
工厂接受一个name
和value
参数。以下示例配置AddResponseHeader``GatewayFilter
:
示例 18.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
:
示例 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
工厂
DedupeResponseHeader GatewayFilter 工厂接受一个name
参数和一个可选的strategy
参数。name
可以包含一个以空格分隔的标题名称列表。下面的示例配置DedupeResponseHeader``GatewayFilter
:
示例 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
在网关 CORS 逻辑和下游逻辑都添加响应头的情况下,这将删除重复的Access-Control-Allow-Credentials
和Access-Control-Allow-Origin
响应头的值。
DedupeResponseHeader
过滤器还接受一个可选的strategy
参数。可接受的值是RETAIN_FIRST
(默认)、RETAIN_LAST
和RETAIN_UNIQUE
。
# 6.5. Spring Cloud CircuitBreaker GatewayFilter Factory
Spring Cloud断路器网关过滤器工厂使用 Spring Cloud断路器 API 将网关路由封装在断路器中。 Spring Cloud Circuitbreaker 支持可与 Spring Cloud Gateway 一起使用的多个库。 Spring Cloud支持开箱即用的弹性 4J。
要启用 Spring Cloud电路断路器过滤器,你需要在 Classpath 上放置spring-cloud-starter-circuitbreaker-reactor-resilience4j
。以下示例配置了 Spring Cloud电路断路器GatewayFilter
:
示例 21.application.yml
spring:
cloud:
gateway:
routes:
- id: circuitbreaker_route
uri: https://example.org
filters:
- CircuitBreaker=myCircuitBreaker
要配置断路器,请参阅你正在使用的底层断路器实现的配置。
Spring Cloud电路断路器过滤器还可以接受可选的fallbackUri
参数。目前,只支持forward:
模式 URI。如果回退被调用,请求将被转发到与 URI 匹配的控制器。下面的示例配置了这种回退:
示例 22.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 中做了相同的事情:
例 23.应用程序.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负载平衡器负载平衡(由目标 URI 上的lb
前缀定义)。
主要的场景是使用fallbackUri
在网关应用程序中定义内部控制器或处理程序。但是,你也可以将请求重新路由到外部应用程序中的控制器或处理程序,如下所示:
示例 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:9994
predicates:
- Path=/fallback
在此示例中,网关应用程序中没有fallback
端点或处理程序。然而,在另一个应用程序中有一个,注册在[localhost:9994](http://localhost:9994)
下。
在请求被转发到 Fallback 的情况下, Spring Cloud Circuitbreaker 网关过滤器还提供了导致它的Throwable
。它被添加到ServerWebExchange
中,作为ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR
属性,该属性可以在处理网关应用程序内的回退时使用。
对于外部控制器/处理程序场景,可以添加带有异常详细信息的头。你可以在FallbackHeaders GatewayFilter 工厂部分中找到有关这样做的更多信息。
# 6.5.1.按状态码切断断路器
在某些情况下,你可能希望基于从其封装的路由返回的状态码来跳闸断路器。断路器配置对象获取一系列状态代码,如果返回这些代码,将导致断路器跳闸。在设置要跳闸的状态码时,可以使用带有状态码值的整数,也可以使用HttpStatus
枚举的字符串表示。
示例 25.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"
例 26.应用程序.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();
}
# 6.6.FallbackHeaders``GatewayFilter
工厂
FallbackHeaders
工厂允许你在转发到外部应用程序中的fallbackUri
的请求的标题中添加 Spring Cloud Circuitbreaker 执行异常详细信息,如下所示:
示例 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:9994
predicates:
- Path=/fallback
filters:
- name: FallbackHeaders
args:
executionExceptionTypeHeaderName: Test-Header
在此示例中,在运行断路器时发生执行异常之后,请求被转发到在localhost:9994
上运行的应用程序中的fallback
端点或处理程序。带有异常类型、消息和(如果可用的话)根原因异常类型和消息的头将由FallbackHeaders
过滤器添加到该请求中。
你可以通过设置以下参数的值(以它们的默认值显示)来覆盖配置中的头的名称:
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
工厂
MapRequestHeader``GatewayFilter
工厂接受fromHeader
和toHeader
参数。它创建一个新的命名头(toHeader
),并从传入的 HTTP 请求中从现有的命名头(fromHeader
)中提取该值。如果输入标头不存在,则过滤器不会产生任何影响。如果新的命名标头已经存在,那么它的值将被新的值扩充。以下示例配置MapRequestHeader
:
示例 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
头更新其值。
# 6.8.PrefixPath``GatewayFilter
工厂
PrefixPath``GatewayFilter
工厂接受一个prefix
参数。以下示例配置PrefixPath``GatewayFilter
:
示例 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
工厂
PreserveHostHeader``GatewayFilter
工厂没有参数。此筛选器设置一个请求属性,路由筛选器将检查该属性以确定是否应发送原始的主机头,而不是由 HTTP 客户机确定的主机头。以下示例配置PreserveHostHeader``GatewayFilter
:
示例 30.application.yml
spring:
cloud:
gateway:
routes:
- id: preserve_host_route
uri: https://example.org
filters:
- PreserveHostHeader
# 6.10.RequestRateLimiter``GatewayFilter
工厂
RequestRateLimiter``GatewayFilter
工厂使用RateLimiter
实现来确定是否允许当前请求继续进行。如果不是,则返回HTTP 429 - Too Many Requests
(默认情况下)的状态。
该过滤器接受一个可选的keyResolver
参数和特定于速率限制器的参数(将在本节后面描述)。
keyResolver
是实现KeyResolver
接口的 Bean。在配置中,使用 spel 通过名称引用 Bean。#{@myKeyResolver}
是一个 spel 表达式,它引用名为myKeyResolver
的 Bean。下面的清单显示了KeyResolver
接口:
例 31.keyresolver.java
public interface KeyResolver {
Mono<String> resolve(ServerWebExchange exchange);
}
KeyResolver
接口让可插入策略派生限制请求的键。在未来的里程碑版本中,将会有一些KeyResolver
实现。
KeyResolver
的默认实现是PrincipalNameKeyResolver
,它从ServerWebExchange
检索Principal
并调用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
属性来调整此行为。
RequestRateLimiter 不能使用“shortcut”符号进行配置。下面的示例是无效:示例 32.application.properties <br/># INVALID SHORTCUT CONFIGURATION<br/>spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2, #{@userkeyresolver}<br/> |
---|
# 6.1 0.1.RedisRateLimiter
Redis 实现基于在Stripe (opens new window)上完成的工作。它需要使用spring-boot-starter-data-redis-reactive
Spring 引导启动器。
使用的算法是令牌桶算法 (opens new window)。
redis-rate-limiter.replenishRate
属性是你希望用户在不删除任何请求的情况下每秒可以执行多少个请求。这是令牌桶被填满的速率。
redis-rate-limiter.burstCapacity
属性是用户在一秒钟内被允许执行的最大请求数。这是令牌桶可以容纳的令牌数量。将此值设置为零将阻止所有请求。
redis-rate-limiter.requestedTokens
属性是一个请求需要多少令牌。这是每个请求从 bucket 中获取的令牌的数量,默认为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
的限制。
示例 33.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:
例 34.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 表达式,它引用名为myRateLimiter
的 Bean。下面的清单定义了一个速率限制器,该限制器使用上一个清单中定义的KeyResolver
:
示例 35.application.yml
spring:
cloud:
gateway:
routes:
- id: requestratelimiter_route
uri: https://example.org
filters:
- name: RequestRateLimiter
args:
rate-limiter: "#{@myRateLimiter}"
key-resolver: "#{@userKeyResolver}"
# 6.11.RedirectTo``GatewayFilter
工厂
RedirectTo``GatewayFilter
工厂接受两个参数,status
和url
。status
参数应该是 300 系列重定向 HTTP 代码,例如 301.url
参数应该是一个有效的 URL。这是Location
标头的值。对于相对重定向,应该使用uri: no://op
作为路由定义的 URI。下面的列表配置了RedirectTo``GatewayFilter
:
示例 36.application.yml
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- RedirectTo=302, https://acme.org
这将发送带有Location:https://acme.org
头的状态 302 来执行重定向。
# 6.12.TheRemoveRequestHeader
GatewayFilter Factory
RemoveRequestHeader``GatewayFilter
工厂接受一个name
参数。它是要删除的标头的名称。下面的列表配置了RemoveRequestHeader``GatewayFilter
:
示例 37.application.yml
spring:
cloud:
gateway:
routes:
- id: removerequestheader_route
uri: https://example.org
filters:
- RemoveRequestHeader=X-Request-Foo
这将在向下游发送X-Request-Foo
头之前删除它。
# 6.13.RemoveResponseHeader``GatewayFilter
工厂
RemoveResponseHeader``GatewayFilter
工厂接受一个name
参数。它是要删除的标头的名称。下面的列表配置了RemoveResponseHeader``GatewayFilter
:
示例 38.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
配置该过滤器一次,并将其应用于所有路由。
# 6.14.RemoveRequestParameter``GatewayFilter
工厂
RemoveRequestParameter``GatewayFilter
工厂接受一个name
参数。它是要删除的查询参数的名称。下面的示例配置RemoveRequestParameter``GatewayFilter
:
示例 39.application.yml
spring:
cloud:
gateway:
routes:
- id: removerequestparameter_route
uri: https://example.org
filters:
- RemoveRequestParameter=red
这将在向下游发送red
参数之前删除该参数。
# 6.15.RewritePath``GatewayFilter
工厂
RewritePath``GatewayFilter
工厂接受一个路径regexp
参数和一个replacement
参数。这使用 Java 正则表达式以灵活的方式重写请求路径。下面的列表配置了RewritePath``GatewayFilter
:
示例 40.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.16.RewriteLocationResponseHeader``GatewayFilter
工厂
RewriteLocationResponseHeader``GatewayFilter
工厂修改Location
响应头的值,通常是为了去掉后台特定的细节。它需要stripVersionMode
、locationHeaderName
、hostValue
和protocolsRegex
参数。下面的列表配置了RewriteLocationResponseHeader``GatewayFilter
:
示例 41.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](https://api.example.com/some/object/name)
的请求,Location
的响应头值[object-service.prod.example.net/v2/some/object/id](https://object-service.prod.example.net/v2/some/object/id)
被重写为[api.example.com/some/object/id](https://api.example.com/some/object/id)
。
stripVersionMode
参数具有以下可能的值:NEVER_STRIP
、AS_IN_REQUEST
(默认)和ALWAYS_STRIP
。
NEVER_STRIP
:即使原始请求路径不包含版本,也不会剥离版本。AS_IN_REQUEST
只有当原始请求路径不包含版本时,才会剥离版本。ALWAYS_STRIP
即使原始请求路径包含版本,版本也总是被剥离。
如果提供了hostValue
参数,则用于替换响应host:port
头的host:port
部分。如果没有提供,则使用Host
请求头的值。
参数protocolsRegex
必须是一个有效的 regexString
,协议名称与该 regex 匹配。如果不匹配,过滤器就不会做任何事情。默认值为http|https|ftp|ftps
。
# 6.17.RewriteResponseHeader``GatewayFilter
工厂
RewriteResponseHeader``GatewayFilter
工厂接受name
、regexp
和replacement
参数。它使用 Java 正则表达式以一种灵活的方式重写响应头值。以下示例配置RewriteResponseHeader``GatewayFilter
:
示例 42.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
。由于 YAML 规范,你必须使用$\
表示$
。
# 6.18.SaveSession``GatewayFilter
工厂
SaveSession``GatewayFilter
工厂强制执行WebSession::save
操作在此之前向下游转发呼叫。这在使用带有惰性数据存储的Spring Session (opens new window)之类的东西时特别有用,并且需要确保在进行转发调用之前保存了会话状态。以下示例配置SaveSession``GatewayFilter
:
示例 43.application.yml
spring:
cloud:
gateway:
routes:
- id: save_session
uri: https://example.org
predicates:
- Path=/foo/**
filters:
- SaveSession
如果将Spring Security (opens new window)与 Spring 会话集成,并希望确保已将安全细节转发到远程进程,这是至关重要的。
# 6.19.SecureHeaders``GatewayFilter
工厂
SecureHeaders``GatewayFilter
工厂根据这篇博文 (opens new window)中提出的建议,向响应添加了许多标题。
添加了以下标题(以其默认值显示):
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
:
示例 44.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
:
示例 45.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
:
示例 46.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
:
示例 47.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
:
示例 48.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
:
示例 49.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 状态都设置为 401.
你可以将SetStatus``GatewayFilter
配置为从响应中的报头中的代理请求返回原始 HTTP 状态代码。如果配置了以下属性,则会将头添加到响应中:
示例 50.application.yml
spring:
cloud:
gateway:
set-status:
original-status-header-name: original-http-status
# 6.24.StripPrefix``GatewayFilter
工厂
StripPrefix``GatewayFilter
工厂接受一个参数,parts
。parts
参数指示在向下游发送请求之前要从请求中剥离的路径中的部件数量。下面的列表配置了StripPrefix``GatewayFilter
:
示例 51.application.yml
spring:
cloud:
gateway:
routes:
- id: nameRoot
uri: https://nameservice
predicates:
- Path=/name/**
filters:
- StripPrefix=2
当通过网关向/name/blue/red
发出请求时,向nameservice
发出的请求看起来像[nameservice/red](https://nameservice/red)
。
# 6.25.重试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
:get 方法exceptions
:IOException
和TimeoutException
backoff
:禁用
下面的清单配置了重试GatewayFilter
:
示例 52.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 ,而是应该抛出或发出错误信号(例如,通过 Mono.error(ex) 返回值),重试筛选器可以配置为通过重试来处理该筛选器。 |
---|
当在带有主体的任何 HTTP 方法中使用 Retry 过滤器时,主体将被缓存,网关将成为内存约束。主体缓存在由ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR 定义的请求属性中。对象的类型是org.springframework.core.io.buffer.DataBuffer 。 |
---|
一个简化的“shortcut”符号可以添加一个status
和method
。
以下两个例子是等价的:
示例 53.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
工厂可以限制请求到达下游服务。过滤器接受maxSize
参数。maxSize
是DataSize
类型,因此值可以定义为一个数字,后面跟着一个可选的DataUnit
后缀,例如“KB”或“MB”。对于字节,默认值为“B”。它是以字节为单位定义的请求的允许大小限制。下面的列表配置了RequestSize``GatewayFilter
:
示例 54.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
工厂将响应状态设置为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
如果在路由定义中没有作为筛选参数提供,则默认的请求大小设置为 5MB。 |
---|
# 6.27.SetRequestHostHeader``GatewayFilter
工厂
在某些情况下,主机标题可能需要被重写。在这种情况下,SetRequestHostHeader``GatewayFilter
工厂可以用指定的 vaue 替换现有的主机报头。过滤器接受host
参数。下面的列表配置了SetRequestHostHeader``GatewayFilter
:
示例 55.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 。应该返回Mono.empty() ,以便在响应中分配一个缺少的主体。 |
---|
# 6.30.令牌中继GatewayFilter
工厂
令牌中继是 OAuth2 使用者充当客户端并将传入的令牌转发给传出的资源请求的一种方式。使用者可以是纯客户机(如 SSO 应用程序)或资源服务器。
Spring Cloud网关可以将 OAuth2 访问令牌转发到其代理的服务的下游。要将此功能添加到 Gateway,你需要添加TokenRelayGatewayFilterFactory
,如下所示:
app.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网关启用此功能,请添加以下依赖项
org.springframework.boot:spring-boot-starter-oauth2-client
它是如何工作的?{githubmaster}/SRC/main/java/org/springframework/cloud/gateway/security/tokenrelaygatewayfilterfactory.java[filter]从当前经过身份验证的用户中提取一个访问令牌,并将其放在下游请求的请求头中。
有关完整的工作示例,请参见这个项目 (opens new window)。
只有设置了适当的spring.security.oauth2.client.* 属性才会创建TokenRelayGatewayFilterFactory Bean,这将触发创建ReactiveClientRegistrationRepository Bean。 |
---|
TokenRelayGatewayFilterFactory 使用的ReactiveOAuth2AuthorizedClientService 的默认实现使用内存中的数据存储。如果需要更健壮的解决方案,则需要提供自己的实现ReactiveOAuth2AuthorizedClientService 。 |
---|
# 6.31.CacheRequestBody``GatewayFilter
工厂
由于请求体流只能被读取一次,所以需要对请求体流进行缓存。你可以使用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();
}
示例 56.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
。此属性接受一个过滤器列表。以下清单定义了一组默认筛选器:
示例 57.application.yml
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Red, Default-Blue
- PrefixPath=/httpbin
# 7.全局过滤器
GlobalFilter
接口具有与GatewayFilter
相同的签名。这些是有条件地应用于所有路由的特殊过滤器。
该接口及其使用情况可能会在未来的里程碑版本中发生更改。 |
---|
# 7.1.组合全局过滤器和GatewayFilter
排序
当请求与路由匹配时,过滤 Web 处理程序将GlobalFilter
的所有实例和GatewayFilter
的所有特定于路由的实例添加到筛选链中。这个组合的过滤器链通过org.springframework.core.Ordered
接口进行排序,你可以通过实现getOrder()
方法来设置该接口。
Spring 由于云网关对于过滤器逻辑执行区分了“pre”和“post”阶段(参见它是如何工作的),优先级最高的过滤器是“pre”阶段的第一个,“post”阶段的最后一个。
下面的清单配置了一个过滤器链:
例 58.示例 configuration.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;
}
}
# 7.2.前向路由滤波器
ForwardRoutingFilter
在 exchange 属性ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
中查找 URI。如果 URL 具有forward
方案(例如forward:///localendpoint
),则它使用 Spring DispatcherHandler
来处理请求。请求 URL 的路径部分被转发 URL 中的路径覆盖。未修改的原始 URL 被追加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR
属性中的列表中。
# 7.3.ReactiveLoadBalancerClientFilter
ReactiveLoadBalancerClientFilter
在名为ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
的 exchange 属性中查找 URI。如果 URL 具有lb
方案(例如lb://myservice
),则它使用 Spring CloudReactorLoadBalancer
将名称(在本例中为myservice
)解析为实际的主机和端口,并替换相同属性中的 URI。未修改的原始 URL 被追加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR
属性中的列表中。过滤器还查看ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR
属性,以查看它是否等于lb
。如果是这样,也适用同样的规则。下面的清单配置了ReactiveLoadBalancerClientFilter
:
示例 59.application.yml
spring:
cloud:
gateway:
routes:
- id: myRoute
uri: lb://service
predicates:
- Path=/service/**
默认情况下,当ReactorLoadBalancer 无法找到服务实例时,将返回一个503 。通过设置 spring.cloud.gateway.loadbalancer.use404=true ,你可以将网关配置为返回一个404 。 |
---|
从ReactiveLoadBalancerClientFilter 返回的isSecure 值的ServiceInstance 覆盖了向网关提出的请求中指定的方案。 例如,如果请求通过 HTTPS 进入网关,但ServiceInstance 表明它是不安全的,下游请求是在HTTP 上提出的。相反的情况也可以适用。 但是,如果 GATEWAY_SCHEME_PREFIX_ATTR 是在网关配置中为该路由指定的,则前缀被剥离,并且从路由 URL 中得到的方案覆盖了ServiceInstance 配置。 |
---|
网关支持所有的负载平衡器功能。你可以在Spring Cloud Commons documentation (opens new window)中阅读有关它们的更多信息。 |
---|
# 7.4.Netty 路由过滤器
如果ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
Exchange 属性中的 URL 具有http
或https
方案,则运行 Netty 路由过滤器。它使用 nettyHttpClient
发出下游代理请求。将响应放入ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR
exchange 属性中,以便在以后的筛选器中使用。(还有一个实验性的WebClientHttpRoutingFilter
,它执行相同的功能,但不需要 netty。
# 7.5.Netty 写响应过滤器
如果ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR
exchange 属性中有一个 nettyHttpClientResponse
,则运行NettyWriteResponseFilter
。它在所有其他过滤器完成并将代理响应写回网关客户机响应后运行。(还有一个实验性的WebClientWriteResponseFilter
,它执行相同的功能,但不需要 netty。
# 7.6.RouteToRequestUrl
过滤器
如果在ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR
exchange 属性中有一个Route
对象,则运行RouteToRequestUrlFilter
。它根据请求 URI 创建一个新的 URI,但使用Route
对象的 URI 属性进行更新。新的 URI 放在ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
exchange 属性中。
如果 URI 有一个方案前缀,例如lb:ws://serviceid
,则将从 URI 中剥离lb
方案,并将其放置在ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR
中,以便稍后在筛选链中使用。
# 7.7. The Websocket Routing Filter
如果位于ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
Exchange 属性中的 URL 具有ws
或wss
方案,则运行 WebSocket 路由过滤器。它使用 Spring WebSocket 基础设施向下游转发 WebSocket 请求。
你可以通过在 URI 前加上lb
来实现 WebSockets 的负载平衡,比如lb:ws://serviceid
。
如果使用SockJS (opens new window)作为普通 HTTP 的后备,则应该配置普通 HTTP 路由和 WebSocket 路由。 |
---|
下面的清单配置了一个 WebSocket 路由过滤器:
示例 60.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/**
# 7.8.网关指标过滤器
要启用网关度量,可以添加 Spring-boot-starter-actuator 作为项目依赖项。然后,默认情况下,只要属性spring.cloud.gateway.metrics.enabled
未设置为false
,网关指标过滤器就会运行。此过滤器添加了一个名为spring.cloud.gateway.requests
的计时器度量,并带有以下标记:
routeId
:路径 ID。routeUri
:将 API 路由到的 URI。outcome
:结果,按HttpStatus.series (opens new window)分类。status
:返回给客户机的请求的 HTTP 状态。httpStatusCode
:返回给客户机的请求的 HTTP 状态。httpMethod
:用于请求的 HTTP 方法。
此外,通过属性spring.cloud.gateway.metrics.tags.path.enabled
(默认情况下,设置为 false),你可以使用标记激活一个额外的度量指标:
path
:请求的路径。
然后可以从/actuator/metrics/spring.cloud.gateway.requests
中获取这些指标,并且可以轻松地与 Prometheus 集成以创建Grafana (opens new window)dashboard。
要启用 Prometheus 端点,请添加micrometer-registry-prometheus 作为项目依赖项。 |
---|
# 7.9.将交易所标记为路由
在网关路由了ServerWebExchange
之后,它通过在 exchange 属性中添加gatewayAlreadyRouted
,将该 exchange 标记为“路由”。一旦一个请求被标记为路由,其他路由过滤器将不会再次路由该请求,基本上跳过了该过滤器。有一些方便的方法,你可以使用它来标记一个交换为路由,或者检查一个交换是否已经被路由。
ServerWebExchangeUtils.isAlreadyRouted
接受一个ServerWebExchange
对象,并检查它是否已被“路由”。ServerWebExchangeUtils.setAlreadyRouted
接受一个ServerWebExchange
对象,并将其标记为“路由”。
# 8.HttpHeadersFilters
HttpHeadersFilters 在向下游发送请求之前应用于请求,例如在NettyRoutingFilter
中。
# 8.1.转发头过滤器
Forwarded
headers filter 创建一个Forwarded
header 以发送到下游服务。它将当前请求的Host
头、方案和端口添加到任何现有的Forwarded
头。
# 8.2.RemoveHopbyHop Headers 过滤器
RemoveHopByHop
headers 过滤器从转发的请求中删除 header。被删除的头的默认列表来自IETF (opens new window)。
默认删除的标题是:
连接
保持活力
代理身份验证
代理授权
TE
预告片
传输编码
升级
要更改这一点,请将spring.cloud.gateway.filter.remove-hop-by-hop.headers
属性设置为要删除的头名称列表。
# 8.3.XForwarded Headers 过滤器
XForwarded
headers filter 创建了各种X-Forwarded-*
headers 以发送到下游服务。它使用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
# 9.TLS 和 SSL
网关可以通过遵循通常的 Spring 服务器配置来监听 HTTPS 上的请求。下面的示例展示了如何做到这一点:
示例 61.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 后端,则可以通过以下配置将网关配置为信任所有下游证书:
示例 62.application.yml
spring:
cloud:
gateway:
httpclient:
ssl:
useInsecureTrustManager: true
使用不安全的信任管理器不适合于生产。对于产品部署,你可以使用一组已知证书来配置网关,它可以通过以下配置来信任这些证书:
示例 63.application.yml
spring:
cloud:
gateway:
httpclient:
ssl:
trustedX509Certificates:
- cert1.pem
- cert2.pem
如果 Spring Cloud网关没有提供受信任的证书,则使用默认的信任存储区(你可以通过设置javax.net.ssl.trustStore
系统属性来覆盖该存储区)。
# 9.1.TLS 握手
网关维护一个用于路由到后端的客户机池。当通过 HTTPS 进行通信时,客户机发起 TLS 握手。与此握手相关的超时次数很多。你可以配置这些超时可以配置(默认显示)如下:
示例 64.application.yml
spring:
cloud:
gateway:
httpclient:
ssl:
handshake-timeout-millis: 10000
close-notify-flush-timeout-millis: 3000
close-notify-read-timeout-millis: 0
# 10.配置(#configuration)
Spring Cloud网关的配置由RouteDefinitionLocator
实例的集合驱动。下面的清单显示了RouteDefinitionLocator
接口的定义:
例 65.RouteDefinitionLocator.java
public interface RouteDefinitionLocator {
Flux<RouteDefinition> getRouteDefinitions();
}
默认情况下,PropertiesRouteDefinitionLocator
通过使用 Spring boot 的@ConfigurationProperties
机制加载属性。
较早的配置示例都使用快捷方式表示,它使用位置参数而不是命名参数。以下两个例子是等价的:
示例 66.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 数据存储库的RouteDefinitionLocator
实现,例如 Redis、MongoDB 和 Cassandra。
# 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)
你可以通过使用元数据为每个路由配置附加参数,如下所示:
示例 67.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 超时配置(#http-timeouts-configuration)
可以为所有路由配置 HTTP 超时(响应和连接),并为每个特定的路由重写。
# 12.1.全球超时(#global-timeouts)
要配置全局 HTTP 超时:connect-timeout
必须以毫秒为单位指定。response-timeout
必须指定为 java.time.duration
全局 HTTP 超时示例
spring:
cloud:
gateway:
httpclient:
connect-timeout: 1000
response-timeout: 5s
# 12.2.每条路线超时(#per-route-timeouts)
要配置每路由超时: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
将禁用全局response-timeout
值。
- id: per_route_timeouts
uri: https://example.org
predicates:
- name: Path
args:
pattern: /delay/{timeout}
metadata:
response-timeout: -1
# 12.3.Fluent Java Routes API(#fluent-java-routes-api)
为了允许在 Java 中进行简单的配置,RouteLocatorBuilder
Bean 包含了一个 Fluent API。下面的清单展示了它的工作原理:
例 68.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();
}
这种样式还允许更多的自定义谓词断言。由RouteDefinitionLocator
bean 定义的谓词使用逻辑and
进行组合。通过使用 Fluent Java API,你可以在Predicate
类上使用and()
、or()
和negate()
运算符。
# [12.4.路由定义定位器](#the-discoveryclient-route-definition-locator)
你可以将网关配置为基于在DiscoveryClient
兼容服务注册中心注册的服务创建路由。
要启用此功能,请设置spring.cloud.gateway.discovery.locator.enabled=true
,并确保在 Classpath 上启用了实现(例如 Netflix Eureka、Consul 或 ZooKeeper)。
# 12.4.1.为DiscoveryClient
路由配置谓词和筛选器(#configuring-predicates-and-filters-for-discoveryclient-route)
默认情况下,网关为使用DiscoveryClient
创建的路由定义一个谓词和过滤器。
缺省谓词是用模式/serviceId/**
定义的路径谓词,其中serviceId
是来自DiscoveryClient
的服务的 ID。
默认的过滤器是一个重写路径过滤器,regex/serviceId/?(?<remaining>.*)
和替换/${remaining}
。这将在向下游发送请求之前从路径中剥离服务 ID。
如果要自定义DiscoveryClient
路由所使用的谓词或筛选器,请设置spring.cloud.gateway.discovery.locator.predicates[x]
和spring.cloud.gateway.discovery.locator.filters[y]
。这样做时,如果你想保留该功能,则需要确保包含前面显示的缺省谓词和筛选器。下面的示例显示了这是什么样子的:
示例 69.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-access-logs)
要启用反应堆网络访问日志,请设置-Dreactor.netty.http.server.accessLogEnabled=true
。
它必须是一个 Java 系统属性,而不是一个 Spring 引导属性。 |
---|
你可以将日志系统配置为具有一个单独的访问日志文件。下面的示例创建了一个注销配置:
示例 70.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>
# 14.CORS 配置(#cors-configuration)
你可以配置网关来控制 CORS 行为。“全局”CORS 配置是 URL 模式到[[ Spring FrameworkCorsConfiguration
](https://DOCS. Spring.io/ Spring/DOCS/5.0.x/javadoc-api/org/springframework/web/cors/corsconfiguration.html)的映射。以下示例配置 CORS:
示例 71.application.yml
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "https://docs.spring.io"
allowedMethods:
- GET
在前面的示例中,对于所有 GET 请求的路径,允许从源自docs.spring.io
的请求发出 CORS 请求。
要为某些网关路由谓词不处理的请求提供相同的 CORS 配置,请将spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping
属性设置为spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping
。当你试图支持 CORS 的 Preflight 请求,而你的路由谓词不求值到true
时,这是有用的,因为 HTTP 方法是options
。
# 15.执行机构 API(#actuator-api)
执行器端点允许你监视 Spring Cloud网关应用程序并与之交互。要实现远程访问,端点必须是应用程序属性中的enabled (opens new window)和通过 HTTP 或 JMX 公开 (opens new window)。下面的清单展示了如何做到这一点:
示例 72.application.properties
management.endpoint.gateway.enabled=true # default value
management.endpoints.web.exposure.include=gateway
# 15.1.详细执行器格式(#verbose-actuator-format)
Spring Cloud网关中添加了一种新的、更详细的格式。它为每条路由添加了更多细节,允许你查看与每条路由相关的谓词和筛选器,以及可用的任何配置。以下示例配置/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
}
]
默认情况下启用此功能。要禁用它,请设置以下属性:
示例 73.application.properties
spring.cloud.gateway.actuator.verbose.enabled=false
在将来的版本中,这将默认为true
。
# 15.2.检索路由过滤器(#retrieving-route-filters)
本节详细介绍了如何检索路由过滤器,包括:
[[gateway-route-filters]](#gateway-route-filters)
# 15.2.1.全局过滤器(#gateway-global-filters)
要检索应用于所有路由的GET
,请对/actuator/gateway/globalfilters
发出GET
请求。由此产生的反应类似于以下情况:
{
"org.spring[email protected]77856cc5": 10100,
"o[email protected]4f6fd101": 10000,
"or[email protected]32d22650": -1,
"[email protected]6459d9": 2147483647,
"[email protected]5e0": 2147483647,
"[email protected]d23": 0,
"org.s[email protected]135064ea": 2147483637,
"[email protected]23c05889": 2147483646
}
响应包含已到位的全局过滤器的详细信息。对于每个全局过滤器,有一个字符串表示过滤器对象(例如,org.spring[[email protected]](/cdn-cgi/l/email-protection)77856cc5
)和相应的order在过滤器链中。}
# 15.2.2.路由过滤器(#gateway-route-filters)
要检索应用于路由的[GatewayFilter
工厂](#gatewayfilter-factories),对GET
请求/actuator/gateway/routefilters
。由此产生的反应类似于以下情况:
{
"[[email protected] configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null,
"[[email protected] configClass = Object]": null,
"[[email protected] configClass = Object]": null
}
响应包含应用于任何特定路径的GatewayFilter
工厂的详细信息。对于每个工厂,都有一个对应对象的字符串表示(例如,GatewayFilter
)。请注意,null
值是由于端点控制器的实现不完整造成的,因为它试图设置过滤器链中对象的顺序,这不适用于GatewayFilter
工厂对象。
# 15.3.刷新路径缓存(#refreshing-the-route-cache)
要清除路由缓存,请对POST
请求/actuator/gateway/refresh
。该请求返回一个没有响应体的 200.
# 15.4.检索在网关中定义的路由(#retrieving-the-routes-defined-in-the-gateway)
要检索在网关中定义的路由,请对GET
请求/actuator/gateway/routes
。由此产生的反应类似于以下情况:
[{
"route_id": "first_route",
"route_object": {
"predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/[email protected]",
"filters": [
"OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.PreserveHostHeaderGatewayFilterFactory$$Lambda$436/[email protected], order=0}"
]
},
"order": 0
},
{
"route_id": "second_route",
"route_object": {
"predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/[email protected]",
"filters": []
},
"order": 0
}]
响应包含网关中定义的所有路由的详细信息。下表描述了响应的每个元素(每个都是路由)的结构:
Path | Type | 说明 |
---|---|---|
route_id | String | 路线 ID。 |
route_object.predicate | Object | 路线谓词。 |
route_object.filters | Array | [GatewayFilter 工厂](#gatewayfilter-factories)应用于该路由。 |
order | Number | 路线顺序。 |
# 15.5.检索有关特定路线的信息(#gateway-retrieving-information-about-a-particular-route)
要检索有关单个路由的信息,请对GET
请求/actuator/gateway/routes/{id}
(例如,/actuator/gateway/routes/first_route
)。由此产生的反应类似于以下情况:
{
"id": "first_route",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"/first"}
}],
"filters": [],
"uri": "https://www.uri-destination.org",
"order": 0
}
下表描述了响应的结构:
Path | Type | 说明 |
---|---|---|
id | String | 路线 ID。 |
predicates | Array | 路由谓词的集合。每个项定义给定谓词的名称和参数。 |
filters | Array | 应用于路由的过滤器的集合。 |
uri | String | 路线的目的地 URI。 |
order | Number | 路线顺序。 |
# 15.6.创建和删除特定的路由(#creating-and-deleting-a-particular-route)
要创建一个路由,使用指定路由字段的 JSON 主体对POST
请求/gateway/routes/{id_route_to_create}
(参见检索有关特定路线的信息)。
要删除一个路由,请对DELETE
请求/gateway/routes/{id_route_to_delete}
。
# 15.7.回顾:所有端点的列表(#recap-the-list-of-all-endpoints)
下面的 FolloiWNG 表总结了 Spring Cloud网关执行器端点(请注意,每个端点都以/actuator/gateway
作为基本路径):
ID | HTTP Method | 说明 |
---|---|---|
globalfilters | GET | 显示应用于路由的全局筛选器列表。 |
routefilters | GET | 显示应用于特定路径的GatewayFilter 工厂的列表。 |
refresh | POST | 清除路由缓存。 |
routes | GET | 显示在网关中定义的路由列表。 |
routes/{id} | GET | 显示有关特定路线的信息。 |
routes/{id} | POST | 为网关添加了一条新的路径。 |
routes/{id} | DELETE | 从网关删除现有的路由。 |
# 15.8.在多个网关实例之间共享路由(#sharing-routes-between-multiple-gateway-instances)
Spring Cloud网关提供了两种RouteDefinitionRepository
实现方式。第一个是InMemoryRouteDefinitionRepository
,它只存在于一个网关实例的内存中。这种类型的存储库不适合跨多个网关实例填充路由。
为了跨 Spring Cloud网关实例的集群共享路由,可以使用RedisRouteDefinitionRepository
。要启用这种存储库,以下属性必须设置为 true:spring.cloud.gateway.redis-route-definition-repository.enabled
同样,对于 RedisrateLimiter 过滤器工厂,它需要使用 Spring-boot-starter-data-redis-active Spring boot starter。
# 16.故障排除(#troubleshooting)
本节介绍了在使用 Spring Cloud网关时可能出现的常见问题。
# 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)
反应堆网络HttpClient
和HttpServer
可以启用窃听功能。当与将reactor.netty
日志级别设置为DEBUG
或TRACE
相结合时,它可以记录信息,例如通过连接发送和接收的标题和主体。要启用窃听,分别为HttpServer
和HttpClient
设置spring.cloud.gateway.httpclient.wiretap=true
。
# 17.开发者指南(#developer-guide)
这些是编写网关的一些自定义组件的基本指南。
# 17.1.编写自定义路由谓词工厂(#writing-custom-route-predicate-factories)
为了编写路由谓词,你需要将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.编写自定义网关过滤器工厂(#writing-custom-gatewayfilter-factories)
要编写GatewayFilter
,你必须将GatewayFilterFactory
实现为 Bean。你可以扩展一个名为AbstractGatewayFilterFactory
的抽象类。下面的例子说明了如何做到这一点:
例 74.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.在配置中命名自定义过滤器和引用(#naming-custom-filters-and-references-in-configuration)
自定义过滤器类名称应该以GatewayFilterFactory
结尾。
例如,要在配置文件中引用名为Something
的过滤器,该过滤器必须位于名为SomethingGatewayFilterFactory
的类中。
可以创建一个没有GatewayFilterFactory 后缀的网关过滤器,例如class AnotherThing 。在配置文件中,这个过滤器可以被引用为 AnotherThing 。这是不是所支持的命名约定,该语法可能会在将来的版本中删除。请更新过滤器名称以使其兼容。 |
---|
# 17.3.编写自定义全局过滤器(#writing-custom-global-filters)
要编写自定义的全局过滤器,你必须将class AnotherThing
接口实现为 Bean。这将过滤器应用于所有请求。
以下示例分别展示了如何设置全局 pre 和 post 过滤器:
@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();
}
# 18. Building a Simple Gateway by Using Spring MVC or Webflux(#building-a-simple-gateway-by-using-spring-mvc-or-webflux)
下面描述了一种替代样式的网关。以前的文件都不适用于下面的内容。 |
---|
Spring Cloud网关提供了一种名为ProxyExchange
的实用对象。你可以在常规的 Spring Web 处理程序中使用它作为方法参数。它通过镜像 HTTP 动词的方法支持基本的下游 HTTP 交换。对于 MVC,它还支持通过forward()
方法转发到本地处理程序。要使用ProxyExchange
,在 Classpath 中包含正确的模块(spring-cloud-gateway-mvc
或spring-cloud-gateway-webflux
)。
下面的 MVC 示例将请求代理到/test
下游的远程服务器:
@RestController
@SpringBootApplication
public class GatewaySampleApplication {
@Value("${remote.home}")
private URI home;
@GetMapping("/test")
public ResponseEntity<?> proxy(ProxyExchange<byte[]> proxy) throws Exception {
return proxy.uri(home.toString() + "/image/png").get();
}
}
下面的示例对 WebFlux 做了相同的处理:
@RestController
@SpringBootApplication
public class GatewaySampleApplication {
@Value("${remote.home}")
private URI home;
@GetMapping("/test")
public Mono<ResponseEntity<?>> proxy(ProxyExchange<byte[]> proxy) throws Exception {
return proxy.uri(home.toString() + "/image/png").get();
}
}
ProxyExchange
上的便利方法使处理程序方法能够发现并增强传入请求的 URI 路径。例如,你可能希望提取路径的尾随元素,以便向下游传递它们:
@GetMapping("/proxy/path/**")
public ResponseEntity<?> proxyPath(ProxyExchange<byte[]> proxy) throws Exception {
String path = proxy.path("/proxy/path/");
return proxy.uri(home.toString() + "/foos/" + path).get();
}
Spring MVC 和 WebFlux 的所有特性都可用于网关处理程序方法。因此,例如,你可以插入请求头和查询参数,并且可以通过映射注释中的声明来约束传入的请求。有关这些特性的更多详细信息,请参见 Spring MVC 中ProxyExchange
的文档。
可以使用ProxyExchange
上的header()
方法向下游响应添加标题。
你还可以通过向get()
方法(和其他方法)添加一个映射器来操作响应头(以及响应中喜欢的任何其他方法)。映射器是一个Function
,它接收传入的ResponseEntity
并将其转换为传出的。
为“敏感”头(默认情况下,cookie
和authorization
)和“代理”头(x-forwarded-*
)提供了一流的支持。
# 19.配置属性(#configuration-properties)
要查看所有 Spring Cloud网关相关配置属性的列表,请参见附录。