Spring cloud gateway微服务网关
**2.2.2.发布**
该项目提供了一个在Spring生态系统之上构建的API网关,包括:Spring 5,Spring Boot 2和Project Reactor.Spring Cloud Gateway旨在提供一种简单而有效的方法来路由到API,并为它们提供跨领域的关注点,例如:安全性,监视/指标和弹性.
## 1.依赖Spring Cloud Gateway
要将Spring Cloud Gateway包括在您的项目中,请使用启动器.
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
```
有关使用当前Spring Cloud Release Train设置构建系统的详细信息,请参见[Spring Cloud Project页面](https://projects.spring.io/spring-cloud/).
如果包括启动器,但不希望启用网关,请设置
```properties
spring.cloud.gateway.enabled=false
```
> Spring Cloud Gateway是基于[Spring Boot 2.x](https://spring.io/projects/spring-boot#learn),[Spring WebFlux](https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html)和[Project Reactor ](https://projectreactor.io/docs)[构建的](https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html).结果,当您使用Spring Cloud Gateway时,许多您熟悉的同步库(例如,Spring Data和Spring Security)和patterns可能不适用.如果您不熟悉这些项目,建议您在使用Spring Cloud Gateway之前先阅读它们的文档以熟悉一些新概念.
>
> Spring Cloud Gateway需要Spring Boot和Spring Webflux提供的Netty运行时.它不能在传统的Servlet容器中或作为WAR构建时使用.
## 2.词汇表
- **路线**:网关的基本构建块.它由ID,目标URI,谓词集合和过滤器集合定义.如果聚合谓词为true,则匹配路由.
- **谓词**:这是[Java 8 Function谓词](https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html).输入类型是[Spring Framework`ServerWebExchange`](https://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/server/ServerWebExchange.html).这使您可以匹配HTTP请求中的所有内容,例如标头或参数.
- **Filter**:这些是使用特定工厂构造的[Spring Framework`GatewayFilter`](https://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/server/GatewayFilter.html)实例.在这里,您可以在发送下游请求之前或之后修改请求和响应.
## 3.工作原理
下图从总体上概述了Spring Cloud Gateway的工作方式:
![Spring Cloud网关图]()
客户端向Spring Cloud Gateway发出请求.如果网关处理程序映射确定请求与路由匹配,则将其发送到网关Web处理程序.该处理程序通过特定于请求的过滤器链来运行请求.筛选器由虚线分隔的原因是,筛选器可以在发送代理请求之前和之后运行逻辑.所有“pre”过滤器逻辑均被执行.然后发出代理请求.发出代理请求后,将运行“post”过滤器逻辑.
> 在没有端口的路由中定义的URI,HTTP和HTTPS URI的默认端口值分别为80和443.
## 4.配置谓词和过滤
有两种配置谓词和过滤器的方法:快捷方式和完全扩展的参数.下面的大多数示例都使用快捷方式.
名称和自变量名称将`code`在每个部分的第一个或两个中列出.参数通常按快捷方式配置所需的顺序列出.
### 4.1.快捷方式配置
快捷方式配置由过滤器名称识别,后跟等号(`=`),后跟以逗号(`,`)分隔的参数值.
application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- Cookie=mycookie,mycookievalue
```
先前的示例`Cookie`使用两个参数(cookie名称`mycookie`和match的值)定义了Route Predicate Factory `mycookievalue`.
### 4.2.参数形式
完全扩展的参数看起来更像带有名称/值对的标准Yaml配置.通常,将有一个`name`钥匙和一个`args`钥匙.的`args`关键是地图**值对的配置谓词或过滤器.
application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- name: Cookie
args:
name: mycookie
regexp: mycookievalue
```
这是`Cookie`上面显示的谓词的快捷方式配置的完整配置.
## 5.路由谓词工厂
Spring Cloud Gateway将路由作为Spring WebFlux `HandlerMapping`基础架构的一部分进行匹配.Spring Cloud Gateway包括许多内置的路由谓词工厂.所有这些谓词都与HTTP请求的不同属性匹配.您可以将多个路由谓词工厂与逻辑`and`语句结合使用.
### 5.1.After
所述`After`路线谓词工厂有一个参数,一个`datetime`(其是Java `ZonedDateTime`).该谓词匹配在指定日期时间之后发生的请求.下面的示例配置路由后谓词:
例子1. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2020-04-02T15:14:19.052+08:00[Asia/Shanghai]
```
这条路线符合2017年1月20日17:42山区时间(丹佛)之后的任何请求.
2017-01-20T17:42:47.789-07:00[America/Denver]
### 5.2.Before
所述`Before`路线谓词工厂有一个参数,一个`datetime`(其是Java `ZonedDateTime`).该谓词匹配在指定之前发生的请求`datetime`.以下示例配置了路由前谓词:
例子2. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: before_route
uri: https://example.org
predicates:
- Before=2020-04-02T15:14:19.052+08:00[Asia/Shanghai]
```
这条路线符合2017年1月20日17:42山区时间(丹佛)之前的任何要求.
2017-01-20T17:42:47.789-07:00[America/Denver]
### 5.3.Between
该`Between`路线谓词工厂有两个参数,`datetime1`并且`datetime2` 这是Java `ZonedDateTime`对象.该谓词匹配在之后`datetime1`和之前发生的请求`datetime2`.该`datetime2`参数必须是后`datetime1`.以下示例配置了路由之间的谓词:
例子3. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: between_route
uri: https://example.org
predicates:
- Between=2020-04-01T12:00:00.000+08:00[Asia/Shanghai],2020-04-02T00:00:00.000+08:00[Asia/Shanghai]
```
该路线与2017年1月20日山区时间(丹佛)之后和2017年1月21日17:42山区时间(丹佛)之后的任何请求相匹配.这对于维护时段可能很有用.
### 5.4.Cookie
所述`Cookie`路线谓词工厂采用两个参数,该cookie `name`和`regexp`(其是Java正则表达式).该谓词匹配具有给定名称且其值与正则表达式匹配的cookie.以下示例配置Cookie路由谓词工厂:
例子4. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p
```
此路由匹配具有名称为`chocolate`与`ch.p`正则表达式匹配的cookie的请求.
### 5.5.Header
所述`Header`路线谓词工厂采用两个参数,报头`name`和一个`regexp`(其是Java正则表达式).该谓词与具有给定名称且其值与正则表达式匹配的标头匹配.以下示例配置标头路由谓词:
例子5. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://example.org
predicates:
- Header=X-Request-Id, \d+
```
如果请求具有名为`X-Request-Id`其值与`\d+`正则表达式匹配的标头(即,其值为一个或多个数字),则此路由匹配.
### 5.6.Host
该`Host`路线谓词工厂需要一个参数:主机名的列表`patterns`.该模式是带有`.`分隔符的Ant样式的模式.谓词与`Host`匹配模式的标头匹配.以下示例配置主机路由谓词:
例子6. application.yml
```yaml
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`或`beta.somehost.org`或`www.anotherhost.org`.
该谓词提取URI模板变量(例如`sub`,在前面的示例中定义的)作为名称和值的映射,并`ServerWebExchange.getAttributes()`使用中定义的键将其放在中`ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE`.这些值可供[工厂](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#gateway-route-filters)使用[`GatewayFilter`](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#gateway-route-filters)
### 5.7.Method
所述`Method`路线谓词厂需要`methods`的参数,它是一个或多个参数:HTTP方法来匹配.以下示例配置方法路由谓词:
例子7. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST
```
如果请求方法是GET或POST则此路由匹配.
### 5.8.Path
该`Path`路线谓词厂有两个参数:春天的列表`PathMatcher` `patterns`和一个可选的标志叫`matchOptionalTrailingSeparator`.以下示例配置路径路由谓词:
例子8. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: path_route
uri: https://example.org
predicates:
- Path=/red/{segment},/blue/{segment}
```
如匹配`/red/1`或`/red/blue`或`/blue/green`
该谓词提取URI模板变量(例如`segment`,在前面的示例中定义的)作为名称和值的映射,并`ServerWebExchange.getAttributes()`使用中定义的键将其放在中`ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE`.这些值可供[工厂](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#gateway-route-filters)使用[`GatewayFilter`](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#gateway-route-filters)
可以使用实用程序方法(称为`get`)来简化对这些变量的访问.下面的示例演示如何使用该`get`方法:
```java
Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);
String segment = uriVariables.get("segment");
```
### 5.9.Query
所述`Query`路线谓词工厂采用两个参数:所要求的`param`和可选的`regexp`(其是Java正则表达式).以下示例配置查询路由谓词:
例子9. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=green
```
如果请求包含`green`查询参数,则前面的路由匹配.
application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=red, gree.
```
如果请求包含一个前述路线匹配`red`,其值相匹配的查询参数`gree.`的regexp,所以`green`和`greet`将匹配.
### 5.10.RemoteAddr
所述`RemoteAddr`路线谓词工厂需要的列表(分钟尺寸1) `sources`,其是CIDR的表示法(IPv4或IPv6)的字符串,如`192.168.0.1/16`(其中`192.168.0.1`是一个IP地址和`16`一个子网掩码).以下示例配置一个RemoteAddr路由谓词:
例子10. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: https://example.org
predicates:
- RemoteAddr=192.168.1.1/24
```
如果请求的远程地址为,则此路由匹配`192.168.1.10`.
### 5.11.Weight
该`Weight`路线谓词工厂有两个参数:`group`和`weight`(一个int).权重是按组计算的.以下示例配置权重路由谓词:
例子11. application.yml
```yaml
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](https://weighthigh.org/),将大约20%的流量[转发](https://weighlow.org/)到[weightlow.org.](https://weighlow.org/)
#### 5.11.1.修改远程地址的解析方式
默认情况下,RemoteAddr路由谓词工厂使用传入请求中的远程地址.如果Spring Cloud Gateway位于代理层之后,则可能与实际的客户端IP地址不匹配.
您可以通过设置custom来定制解析远程地址的方式`RemoteAddressResolver`.Spring cloud gateway附带了一个基于的关闭一个非默认的远程地址解析器X-Forwarded-For 头,`XForwardedRemoteAddressResolver`.
`XForwardedRemoteAddressResolver` 有两个静态构造函数方法,它们采用不同的安全性方法:
- `XForwardedRemoteAddressResolver::trustAll`返回一个`RemoteAddressResolver`始终采用`X-Forwarded-For`标头中找到的第一个IP地址的.这种方法容易受到欺骗,因为恶意客户端可能会为设置初始值,`X-Forwarded-For`解析器会接受该初始值.
- `XForwardedRemoteAddressResolver::maxTrustedIndex`采用与Spring Cloud Gateway前面运行的受信任基础架构数量相关的索引.如果例如只能通过HAProxy访问Spring Cloud Gateway,则应使用值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实现相同的配置:
例子12. GatewayConfig.java
```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")
)
```
## 6. GatewayFilter
路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应.路由过滤器适用于特定路由.Spring Cloud Gateway包括许多内置的GatewayFilter工厂.
> 有关如何使用以下任何过滤器的更多详细示例,请查看[单元测试](https://github.com/spring-cloud/spring-cloud-gateway/tree/master/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory).
### 6.1.AddRequestHeader
该`AddRequestHeader` `GatewayFilter`工厂需要`name`和`value`参数.以下示例配置了`AddRequestHeader` `GatewayFilter`:
例子13. application.yml
```yaml
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`使用变量的:
例子14. application.yml
```yaml
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
该`AddRequestParameter` `GatewayFilter`工厂需要`name`和`value`参数.以下示例配置了`AddRequestParameter` `GatewayFilter`:
例子15. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: https://example.org
filters:
- AddRequestParameter=red, blue
```
这将添加`red=blue`到所有匹配请求的下游请求的查询字符串中.
`AddRequestParameter`了解用于匹配路径或主机的URI变量.URI变量可以在值中使用,并在运行时扩展.以下示例配置了`AddRequestParameter` `GatewayFilter`使用变量的:
例子16. application.yml
```yaml
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
该`AddResponseHeader` `GatewayFilter`工厂需要`name`和`value`参数.以下示例配置了`AddResponseHeader` `GatewayFilter`:
例子17. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: add_response_header_route
uri: https://example.org
filters:
- AddResponseHeader=X-Response-Red, Blue
```
这会将`X-Response-Foo:Bar`标头添加到所有匹配请求的下游响应的标头中.
`AddResponseHeader`知道用于匹配路径或主机的URI变量.URI变量可以在值中使用,并在运行时扩展.以下示例配置了`AddResponseHeader` `GatewayFilter`使用变量的:
例子18. application.yml
```yaml
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
DedupeResponseHeader GatewayFilter工厂采用一个`name`参数和一个可选`strategy`参数.`name`可以包含以空格分隔的标题名称列表.以下示例配置了`DedupeResponseHeader` `GatewayFilter`:
例子19. application.yml
```yaml
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.Hystrix
> [Netflix已将Hystrix置于维护模式](https://cloud.spring.io/spring-cloud-netflix/multi/multi__modules_in_maintenance_mode.html).我们建议您将[Spring Cloud CircuitBreaker网关过滤器](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#spring-cloud-circuitbreaker-filter-factory)与Resilience4J一起使用,因为在将来的版本中将不再支持Hystrix.
[Hystrix](https://github.com/Netflix/Hystrix)是Netflix的一个库,用于实现[断路器模式](https://martinfowler.com/bliki/CircuitBreaker.html).将`Hystrix` `GatewayFilter`让你介绍断路器和网关路由,保护您的服务从级联故障,让你提供下游故障时备用的响应.
要`Hystrix` `GatewayFilter`在项目中启用实例,请`spring-cloud-starter-netflix-hystrix`从[Spring Cloud Netflix](https://cloud.spring.io/spring-cloud-netflix/)添加依赖项.
该`Hystrix` `GatewayFilter`工厂需要一个`name`参数,它是的名称`HystrixCommand`.以下示例配置Hystrix `GatewayFilter`:
例子20. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: hystrix_route
uri: https://example.org
filters:
- Hystrix=myCommandName
```
这会将其余过滤器包装在`HystrixCommand`命令名称为的中`myCommandName`.
Hystrix过滤器还可以接受可选`fallbackUri`参数.当前,仅`forward:`支持计划的URI.如果调用了后备,则请求将转发到与URI匹配的控制器.以下示例配置了这种后备:
例子21. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: hystrix_route
uri: lb://backing-service:8088
predicates:
- Path=/consumingserviceendpoint
filters:
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: forward:/incaseoffailureusethis
- RewritePath=/consumingserviceendpoint, /backingserviceendpoint
```
`/incaseoffailureusethis`调用Hystrix后备时,它将转发到URI.请注意,此示例还演示了(可选)Spring Cloud Netflix Ribbon负载平衡(`lb`在目标URI上定义了前缀).
主要方案是对`fallbackUri`网关应用程序中的内部控制器或处理程序使用.但是,您还可以将请求重新路由到外部应用程序中的控制器或处理程序,如下所示:
例子22. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: ingredients
uri: lb://ingredients
predicates:
- Path=//ingredients/**
filters:
- name: Hystrix
args:
name: fetchIngredients
fallbackUri: forward:/fallback
- id: ingredients-fallback
uri: http://localhost:9994
predicates:
- Path=/fallback
```
在此示例中,`fallback`网关应用程序中没有端点或处理程序.但是,另一个应用程序中有一个,在处注册`localhost:9994`.
如果将请求转发到后备,则Hystrix网关过滤器还会提供`Throwable`引起请求的.它`ServerWebExchange`作为`ServerWebExchangeUtils.HYSTRIX_EXECUTION_EXCEPTION_ATTR`属性添加到中,您可以在处理网关应用程序中的后备时使用该属性.
对于外部控制器/处理程序方案,您可以添加带有异常详细信息的标头.您可以在[FallbackHeaders GatewayFilter Factory部分中](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#fallback-headers)找到有关此操作的更多信息.
您可以使用应用程序属性将Hystrix设置(例如超时)配置为全局默认值或逐个路由,如[Hystrix Wiki](https://github.com/Netflix/Hystrix/wiki/Configuration)上所述.
要为前面显示的示例路由设置五秒钟的超时时间,可以使用以下配置:
例子23. application.yml
```yaml
hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds: 5000
```
### 6.6.CircuitBreaker
Spring Cloud CircuitBreaker GatewayFilter工厂使用Spring Cloud CircuitBreaker API将网关路由包装在断路器中.Spring Cloud CircuitBreaker支持可与Spring Cloud Gateway一起使用的两个库Hystrix和Resilience4J.由于Netflix已将Hystrix置于仅维护模式,因此建议您使用Resilience4J.
要启用Spring Cloud CircuitBreaker过滤器,您需要将`spring-cloud-starter-circuitbreaker-reactor-resilience4j`或`spring-cloud-starter-netflix-hystrix`放置在类路径上.以下示例配置了Spring Cloud CircuitBreaker `GatewayFilter`:
例子24. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: circuitbreaker_route
uri: https://example.org
filters:
- CircuitBreaker=myCircuitBreaker
```
要配置断路器,请参阅所使用的基础断路器实现的配置.
- [Resilience4J文档](https://cloud.spring.io/spring-cloud-circuitbreaker/reference/html/spring-cloud-circuitbreaker.html)
- [Hystrix文档](https://cloud.spring.io/spring-cloud-netflix/reference/html/)
Spring Cloud CircuitBreaker过滤器也可以接受可选`fallbackUri`参数.当前,仅`forward:`支持计划的URI.如果调用了后备,则请求将转发到与URI匹配的控制器.以下示例配置了这种后备:
例子25. application.yml
```yaml
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中做同样的事情:
例子26. Application.java
```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 Netflix Ribbon负载平衡(由`lb`目标URI上的前缀定义).
主要方案是使用`fallbackUri`定义网关应用程序中的内部控制器或处理程序.但是,您还可以将请求重新路由到外部应用程序中的控制器或处理程序,如下所示:
例子27. application.yml
```yaml
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网关过滤器还会提供`Throwable`引起请求的.它`ServerWebExchange`作为`ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR`属性添加到中,可以在处理网关应用程序中的后备时使用.
对于外部控制器/处理程序方案,可以添加带有异常详细信息的标头.您可以在[FallbackHeaders GatewayFilter Factory部分中](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#fallback-headers)找到有关此操作的更多信息.
### 6.7.FallbackHeaders
通过`FallbackHeaders`工厂,您可以在转发到`fallbackUri`外部应用程序中的请求的标头中添加Hystrix或Spring Cloud CircuitBreaker执行异常详细信息,如以下情况所示:
例子28. application.yml
```yaml
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"`)
有关电路烧杯和网关的更多信息,请参见[Hystrix GatewayFilter Factory部分](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#hystrix)或[Spring Cloud CircuitBreaker Factory部分](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#spring-cloud-circuitbreaker-filter-factory).
### 6.8.MapRequestHeader
该`MapRequestHeader` `GatewayFilter`工厂采用`fromHeader`和`toHeader`参数.它将创建一个新的命名标头(`toHeader`),然后`fromHeader`从传入的http请求中将其值从现有的命名标头()中提取出来.如果输入标头不存在,则过滤器不起作用.如果新的命名报头已经存在,则其值将使用新值进行扩充.以下示例配置了`MapRequestHeader`:
例子29. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: map_request_header_route
uri: https://example.org
filters:
- MapRequestHeader=Blue, X-Request-Red
```
这会将`X-Request-Red:`标头添加到下游请求中,并带有来自传入HTTP请求`Blue`标头的更新值.
### 6.9.PrefixPath
该`PrefixPath` `GatewayFilter`工厂采用单个`prefix`参数.以下示例配置了`PrefixPath` `GatewayFilter`:
例子30. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- PrefixPath=/mypath
```
这将`/mypath`作为所有匹配请求的路径的增加前缀.因此,`/hello`将向发送请求`/mypath/hello`.
### 6.10.PreserveHostHeader
该`PreserveHostHeader` `GatewayFilter`工厂没有参数.此过滤器设置请求属性,路由过滤器将检查该请求属性,以确定是否应发送原始主机头,而不是由HTTP客户端确定的主机头.以下示例配置了`PreserveHostHeader` `GatewayFilter`:
例子31. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: preserve_host_route
uri: https://example.org
filters:
- PreserveHostHeader
```
### 6.11.RequestRateLimiter
该`RequestRateLimiter` `GatewayFilter`工厂采用的是`RateLimiter`实施以确定当前请求被允许继续进行.如果不是,`HTTP 429 - Too Many Requests`则返回状态(默认).
该过滤器采用一个可选`keyResolver`参数和特定于速率限制器的参数(本节稍后将介绍).
`keyResolver`是实现`KeyResolver`接口的bean .在配置中,使用SpEL按名称引用bean. `#{@myKeyResolver}`是一个SpEL表达式,该表达式引用名为的bean `myKeyResolver`.以下清单显示了该`KeyResolver`接口:
例子32. KeyResolver.java
```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`属性来调整此行为.
> 在`RequestRateLimiter`不与“快捷方式”符号配置.下面的示例*无效*:例子33. application.properties
> #无效的快捷方式配置
> spring.cloud.gateway.routes[0] .filters[0] = RequestRateLimiter = 2,2,#{@ userkeyresolver}
#### 6.11.1.Redis RateLimiter
Redis的实现基于[Stripe](https://stripe.com/blog/rate-limiters)的工作.它需要使用`spring-boot-starter-data-redis-reactive`Spring Boot启动器.
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
```
使用的算法是[令牌桶算法](https://en.wikipedia.org/wiki/Token_bucket).
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`.
例子34. application.yml
```yaml
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:
例子35. Config.java
```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`前面清单中定义的速率限制器:
例子36. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: requestratelimiter_route
uri: https://example.org
filters:
- name: RequestRateLimiter
args:
rate-limiter: "#{@myRateLimiter}"
key-resolver: "#{@userKeyResolver}"
```
### 6.12.RedirectTo
该`RedirectTo` `GatewayFilter`工厂有两个参数,`status`和`url`.该`status`参数应该是300系列重定向HTTP代码,例如301.该`url`参数应该是有效的URL.这是`Location`标题的值.对于相对重定向,您应该将其`uri: no://op`用作路由定义的uri.以下清单配置了一个`RedirectTo` `GatewayFilter`:
例子37. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- RedirectTo=302, https://acme.org
```
这将发送带有`Location:https://acme.org`标头的状态302 以执行重定向.
### 6.13.RemoveRequestHeader
该`RemoveRequestHeader` `GatewayFilter`工厂需要一个`name`参数.它是要删除的标题的名称.以下清单配置了一个`RemoveRequestHeader` `GatewayFilter`:
例子38. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: removerequestheader_route
uri: https://example.org
filters:
- RemoveRequestHeader=X-Request-Foo
```
这将删除`X-Request-Foo`标题,然后再将其发送到下游.
### 6.14.RemoveResponseHeader
该`RemoveResponseHeader` `GatewayFilter`工厂需要一个`name`参数.它是要删除的标题的名称.以下清单配置了一个`RemoveResponseHeader` `GatewayFilter`:
例子39. application.yml
```yaml
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.15.RemoveRequestParameter
该`RemoveRequestParameter` `GatewayFilter`工厂需要一个`name`参数.它是要删除的查询参数的名称.以下示例配置了`RemoveRequestParameter` `GatewayFilter`:
例子40. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: removerequestparameter_route
uri: https://example.org
filters:
- RemoveRequestParameter=red
```
这将删除`red`参数,然后再将其发送到下游.
### 6.16.RewritePath
该`RewritePath` `GatewayFilter`工厂采用的路径`regexp`参数和`replacement`参数.这使用Java正则表达式提供了一种灵活的方式来重写请求路径.以下清单配置了一个`RewritePath` `GatewayFilter`:
例子41. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: rewritepath_route
uri: https://example.org
predicates:
- Path=/foo/**
filters:
- RewritePath=/red(?<segment>/?.*), $\{segment}
```
对于的请求路径`/red/blue`,这会将路径设置为`/blue`发出下游请求之前的路径.请注意,由于YAML规范,`$`应将替换`$\`为.
### 6.17.RewriteLocationResponseHeader
`RewriteLocationResponseHeader` `GatewayFilter`工厂修改的值`Location`响应头,通常摆脱于后端的具体细节.这需要`stripVersionMode`,`locationHeaderName`,`hostValue`,和`protocolsRegex`参数.以下清单配置了一个`RewriteLocationResponseHeader` `GatewayFilter`
例子42. application.yml
```yaml
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`与协议名称匹配的有效regex .如果不匹配,则过滤器不执行任何操作.默认值为`http|https|ftp|ftps`.
### 6.18.RewriteResponseHeader
该`RewriteResponseHeader` `GatewayFilter`工厂需要`name`,`regexp`和`replacement`参数.它使用Java正则表达式以灵活的方式重写响应标头值.以下示例配置了`RewriteResponseHeader` `GatewayFilter`:
例子43. application.yml
```yaml
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.19.SaveSession
*在*向下游转发呼叫*之前*,`SaveSession` `GatewayFilter`工厂会强制执行`WebSession::save`操作.当将诸如[Spring Session之类](https://projects.spring.io/spring-session/)的数据与惰性数据存储一起使用时,这特别有用,您需要确保在进行转发呼叫之前已保存会话状态.以下示例配置了:`SaveSession` `GatewayFilter`
例子44. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: save_session
uri: https://example.org
predicates:
- Path=/foo/**
filters:
- SaveSession
```
如果您将[Spring Security](https://projects.spring.io/spring-security/)与Spring Session 集成在一起,并且想要确保安全性详细信息已转发到远程进程,那么这一点至关重要.
### 6.20.SecureHeaders
根据[此博客文章中](https://blog.appcanary.com/2017/http-security-headers.html)`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.21.SetPath
该`SetPath` `GatewayFilter`工厂采用的路径`template`参数.通过允许路径的模板段,它提供了一种操作请求路径的简单方法.这使用了Spring Framework中的URI模板.允许多个匹配段.以下示例配置了`SetPath` `GatewayFilter`:
例子45. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: setpath_route
uri: https://example.org
predicates:
- Path=/red/{segment}
filters:
- SetPath=/{segment}
```
对于的请求路径`/red/blue`,这会将路径设置为`/blue`发出下游请求之前的路径.
### 6.22.SetRequestHeader
该`SetRequestHeader` `GatewayFilter`工厂采用`name`和`value`参数.以下清单配置了一个`SetRequestHeader` `GatewayFilter`:
例子46. application.yml
```yaml
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`使用变量的:
例子47. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: setrequestheader_route
uri: https://example.org
predicates:
- Host: {segment}.myhost.org
filters:
- SetRequestHeader=foo, bar-{segment}
```
### 6.23.SetResponseHeader
该`SetResponseHeader` `GatewayFilter`工厂采用`name`和`value`参数.以下清单配置了一个`SetResponseHeader` `GatewayFilter`:
例子48. application.yml
```yaml
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`使用变量的:
例子49. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: setresponseheader_route
uri: https://example.org
predicates:
- Host: {segment}.myhost.org
filters:
- SetResponseHeader=foo, bar-{segment}
```
### 6.24.SetStatus
该`SetStatus` `GatewayFilter`工厂采用单个参数,`status`.它必须是有效的Spring `HttpStatus`.它可以是整数值`404`或枚举的字符串表示形式:`NOT_FOUND`.以下清单配置了一个`SetStatus` `GatewayFilter`:
例子50. application.yml
```yaml
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状态代码.如果将头配置为以下属性,则会将其添加到响应中:
例子51. application.yml
```yaml
spring:
cloud:
gateway:
set-status:
original-status-header-name: original-http-status
```
### 6.25.StripPrefix
该`StripPrefix` `GatewayFilter`工厂有1个参数,`parts`.该`parts`参数指示在向下游发送请求之前要从请求中剥离的路径中的零件数.以下清单配置了一个`StripPrefix` `GatewayFilter`:
例子52. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: nameRoot
uri: https://nameservice
predicates:
- Path=/name/**
filters:
- StripPrefix=2
```
通过网关`/name/blue/red`发出请求时,发出的请求`nameservice`看起来像`nameservice/red`.
### 6.26.Retry
该`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`为true,则使用计算退避`prevBackoff * factor`.
`Retry`如果启用了以下默认过滤器配置:
- `retries`:3次
- `series`:5XX系列
- `methods`:GET方法
- `exceptions`:`IOException`和`TimeoutException`
- `backoff`:禁用
以下清单配置了Retry `GatewayFilter`:
例子53. application.yml
```yaml
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`.对象的类型是`org.springframework.core.io.buffer.DataBuffer`.
### 6.27.RequestSize
当请求大小大于允许的限制时,`RequestSize` `GatewayFilter`工厂可以限制请求到达下游服务.过滤器接受一个`maxSize`参数.的`maxSize is a `DataSize`类型,所以值可以被定义为一个数字,后跟一个可选的`DataUnit`后缀,例如“KB”或“MB”.字节的默认值为“ B”.它是请求的允许大小限制,以字节为单位.以下清单配置了一个`RequestSize` `GatewayFilter`:
例子54. application.yml
```yaml
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.28.修改请求正文
您可以使用`ModifyRequestBody`过滤器过滤器在网关向下游发送请求主体之前对其进行修改.
> 只能使用Java DSL来配置此过滤器
以下清单显示了如何修改请求正文`GatewayFilter`:
```java
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("rewrite_request_obj", r -> r.host("**")
.filters(f -> f.prefixPath("/**")
.modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE,
(exchange, body)->Mono.just(new Hello(body.toUpperCase())))).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;
}
}
```
### 6.29.修改响应主体
您可以使用`ModifyResponseBody`过滤器在将响应正文发送回客户端之前对其进行修改.
> 只能使用Java DSL来配置此过滤器.
以下清单显示了如何修改响应正文`GatewayFilter`:
```java
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("rewrite_response_upper", r -> r.host("**")
.filters(f -> f.prefixPath("/**")
.modifyResponseBody(String.class, String.class,
(exchange, body)->Mono.just(body.toUpperCase()))).uri(""))
.build();
}
```
### 6.30.默认过滤器
要添加过滤器并将其应用于所有路由,可以使用`spring.cloud.gateway.default-filters`.此属性采用过滤器列表.以下清单定义了一组默认过滤器:
例子55. application.yml
```yaml
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Red, Default-Blue
- PrefixPath=/httpbin
```
## 7.全局过滤器
该`GlobalFilter`接口具有与相同的签名`GatewayFilter`.这些是特殊过滤器,有条件地应用于所有路由.
> 此接口及其用法可能会在将来的里程碑版本中更改.
### 7.1.GlobalFilter和GatewayFilter顺序
当请求与路由匹配时,过滤Web处理程序会将的所有实例`GlobalFilter`和所有特定`GatewayFilter`于路由的实例添加到过滤器链中.该组合的过滤器链按`org.springframework.core.Ordered`接口排序,您可以通过实现该`getOrder()`方法进行设置.
由于Spring Cloud Gateway区分了执行过滤器逻辑的“前”阶段和“后”阶段(请参阅[工作原理](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#gateway-how-it-works)),因此优先级最高的过滤器是“前”阶段的第一个,而“后”阶段的最后一个-相.
以下清单配置了一个过滤器链:
例子56. ExampleConfiguration.java
```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
将`ForwardRoutingFilter`在交换属性查找一个URI `ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR`.如果该网址具有`forward`方案(例如`forward:///localendpoint`),它将使用Spring `DispatcherHandler`处理请求.请求URL的路径部分被转发URL中的路径覆盖.未经修改的原始URL将附加到`ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR`属性中的列表.
### 7.3.LoadBalancerClientFilter
将`LoadBalancerClientFilter`在交换属性查找一个URI命名`ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR`.如果URL的方案为`lb`(例如`lb://myservice`),它将使用Spring Cloud `LoadBalancerClient`将名称(`myservice`在这种情况下)解析为实际的主机和端口,并在同一属性中替换URI.未经修改的原始URL将附加到`ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR`属性中的列表.过滤器还会在`ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR`属性中查找是否相等`lb`.如果是这样,则适用相同的规则.以下清单配置了一个`LoadBalancerClientFilter`:
例子57. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: myRoute
uri: lb://service
predicates:
- Path=/service/**
```
> More Actions默认情况下,如果在中找不到服务实例`LoadBalancer`,`503`则返回a.您可以`404`通过设置将网关配置为返回`spring.cloud.gateway.loadbalancer.use404=true`.
>
> More Actions从覆盖返回 的`isSecure`值`ServiceInstance`将`LoadBalancer`覆盖对网关的请求中指定的方案.例如,如果请求通过进入网关,`HTTPS` 但`ServiceInstance`指示该请求不安全,则通过进行下游请求 `HTTP`.相反的情况也可以适用.但是,如果`GATEWAY_SCHEME_PREFIX_ATTR`在“网关”配置中为路由指定了该前缀,则将删除前缀,并且路由URL产生的方案将覆盖该`ServiceInstance`配置.
>
> `LoadBalancerClientFilter``LoadBalancerClient`在引擎盖下使用阻挡色带.我们建议您[`ReactiveLoadBalancerClientFilter`改用](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#reactive-loadbalancer-client-filter).您可以通过设置的值切换到它`spring.cloud.loadbalancer.ribbon.enabled`来`false`.
### 7.4.ReactiveLoadBalancerClientFilter
将`ReactiveLoadBalancerClientFilter`在交换属性查找一个URI命名`ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR`.如果URL有一个`lb`方案(例如`lb://myservice`),它将使用Spring Cloud `ReactorLoadBalancer`将名称(`myservice`在此示例中)解析为实际的主机和端口,并在同一属性中替换URI.未经修改的原始URL将附加到`ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR`属性中的列表.过滤器还会在`ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR`属性中查找是否相等`lb`.如果是这样,则适用相同的规则.以下清单配置了一个`ReactiveLoadBalancerClientFilter`:
例子58. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: myRoute
uri: lb://service
predicates:
- Path=/service/**
```
> 缺省情况下,当找不到服务实例时`ReactorLoadBalancer`,将`503`返回a.您可以`404`通过设置将网关配置为返回a `spring.cloud.gateway.loadbalancer.use404=true`.
>
> 从覆盖返回 的`isSecure`值`ServiceInstance`将`ReactiveLoadBalancerClientFilter`覆盖对网关的请求中指定的方案.例如,如果请求通过进入网关,`HTTPS`但`ServiceInstance`指示该请求不安全,则通过进行下游请求`HTTP`.相反的情况也可以适用.但是,如果`GATEWAY_SCHEME_PREFIX_ATTR`在“网关”配置中为路由指定了该前缀,则将删除前缀,并且路由URL产生的方案将覆盖该`ServiceInstance`配置.
### 7.5.网络路由过滤器
如果位于`ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR`交换属性中的URL 具有`http`或`https`方案,则将运行Netty路由筛选器.它使用Netty `HttpClient`发出下游代理请求.响应将放入`ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR`exchange属性中,以供以后的过滤器使用.(也有一个实验`WebClientHttpRoutingFilter`执行相同的功能,但不需要Netty.)
### 7.6.NettyWriteResponseFilter
的`NettyWriteResponseFilter`,如果有一个运行的Netty `HttpClientResponse`在`ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR`交换属性.它在所有其他筛选器完成后运行,并将代理响应写回到网关客户端响应.(也有一个实验`WebClientWriteResponseFilter`执行相同的功能,但不需要Netty.)
### 7.7.RouteToRequestUrl
如果交换属性中有一个`Route`对象`ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR`,则`RouteToRequestUrlFilter`运行.它基于请求URI创建一个新的URI,但使用`Route`对象的URI属性进行更新.新的URI放置在`ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR`exchange属性中.
如果URI具有方案前缀(例如)`lb:ws://serviceid`,则将`lb`方案从URI中剥离并放入中,`ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR`以供稍后在过滤器链中使用.
### 7.8.Websocket
如果位于`ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR`exchange属性中的URL 具有`ws`或`wss`方案,则将运行websocket路由过滤器.它使用Spring WebSocket基础结构向下游转发websocket请求.
你可以用前缀的URI负载平衡的WebSockets `lb`,如`lb:ws://serviceid`.
> 如果您将[SockJS](https://github.com/sockjs)用作常规HTTP的后备,则应配置常规HTTP路由以及websocket路由.
下面的清单配置了一个websocket路由过滤器:
例子59. application.yml
```yaml
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.9.网关指标过滤器
要启用网关指标,请添加spring-boot-starter-actuator作为项目依赖项.然后,默认情况下,只要属性`spring.cloud.gateway.metrics.enabled`未设置为,网关度量过滤器就会运行`false`.该过滤器添加了一个`gateway.requests`带有以下标记的计时器指标:
- `routeId`:路由ID.
- `routeUri`:API路由到的URI.
- `outcome`:结果,按[HttpStatus.Series](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/HttpStatus.Series.html)分类.
- `status`:请求的HTTP状态返回给客户端.
- `httpStatusCode`:请求的HTTP状态返回给客户端.
- `httpMethod`:用于请求的HTTP方法.
然后可以从这些指标中刮取这些指标,`/actuator/metrics/gateway.requests`并且可以轻松地将这些指标与Prometheus集成以创建[Grafana ](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/images/gateway-grafana-dashboard.jpeg)[仪表板](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/gateway-grafana-dashboard.json).
> 要启用Prometheus端点,请添加`micrometer-registry-prometheus`为项目依赖项.
### 7.10.将交换标记为已路由
网关路由a之后`ServerWebExchange`,它会通过添加`gatewayAlreadyRouted` 交换属性来将交换标记为“已路由” .将请求标记为已路由后,其他路由筛选器将不会再次路由请求,实质上会跳过该筛选器.您可以使用多种便捷方法将交换标记为已路由,或者检查交换是否已路由.
- `ServerWebExchangeUtils.isAlreadyRouted`接收一个`ServerWebExchange`对象并检查它是否已被“路由”.
- `ServerWebExchangeUtils.setAlreadyRouted`接收一个`ServerWebExchange`对象并将其标记为“已路由”.
## 8. HttpHeadersFilters
HttpHeadersFilters应用于请求,然后再向下游发送请求,例如在中`NettyRoutingFilter`.
### 8.1.转发的Header过滤器
该`Forwarded`头过滤器创建一个`Forwarded`头发送到下游服务.它将`Host`当前请求的标头,方案和端口添加到任何现有的`Forwarded`标头中.
### 8.2.RemoveHopByHop标头过滤器
该`RemoveHopByHop`头过滤去除转发的请求头.被删除的头的默认列表来自[IETF](https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-14#section-7.1.3).
默认删除的headers为:
- Connection 连接
- Keep-Alive 活着
- Proxy-Authenticate 代理验证
- Proxy-Authorization 代理授权
- TE
- Trailer 预告片
- Transfer-Encoding 传输编码
- Upgrade 升级
要更改此设置,请将`spring.cloud.gateway.filter.remove-non-proxy-headers.headers`属性设置为要删除的标题名称列表.
### 8.3.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`
## 9. TLS和SSL
遵循通常的Spring服务器配置,网关可以侦听HTTPS上的请求.以下示例显示了如何执行此操作:
例子60. application.yml
```yaml
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
```yaml
spring:
cloud:
gateway:
httpclient:
ssl:
useInsecureTrustManager: true
```
使用不安全的信任管理器不适用于生产.对于生产部署,可以使用以下配置为网关配置一组可以信任的已知证书:
例子62. application.yml
```yaml
spring:
cloud:
gateway:
httpclient:
ssl:
trustedX509Certificates:
- cert1.pem
- cert2.pem
```
如果未为Spring Cloud Gateway设置可信证书,则使用默认的信任库(您可以通过设置`javax.net.ssl.trustStore`system属性来覆盖它).
### 9.1.TLS握手
网关维护一个客户端池,该客户端池用于路由到后端.通过HTTPS进行通信时,客户端会启动TLS握手.许多超时与此握手相关联.您可以配置这些超时,可以如下配置(显示默认值):
例子63. application.yml
```yaml
spring:
cloud:
gateway:
httpclient:
ssl:
handshake-timeout-millis: 10000
close-notify-flush-timeout-millis: 3000
close-notify-read-timeout-millis: 0
```
## 10.配置
Spring Cloud Gateway的配置由一系列`RouteDefinitionLocator`实例驱动.以下清单显示了`RouteDefinitionLocator`接口的定义:
例子64. RouteDefinitionLocator.java
```java
public interface RouteDefinitionLocator {
Flux<RouteDefinition> getRouteDefinitions();
}
```
默认情况下,`PropertiesRouteDefinitionLocator`使用Spring Boot的`@ConfigurationProperties`机制来加载属性.
较早的配置示例均使用快捷方式符号,该快捷方式符号使用位置参数而不是命名参数.以下两个示例是等效的:
例子65. application.yml
```yaml
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数据存储库实现,例如Redis,MongoDB和Cassandra.
## 11.路由元数据配置
您可以使用元数据为每个路由配置其他参数,如下所示:
例子66. application.yml
```yaml
spring:
cloud:
gateway:
routes:
- id: route_with_metadata
uri: https://example.org
metadata:
optionName: "OptionValue"
compositeObject:
name: "value"
iAmNumber: 1
```
您可以从交易所获取所有元数据属性,如下所示:
```java
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
// get all metadata properties
route.getMetadata();
// get a single metadata property
route.getMetadata(someKey);
```
## 12. Http超时配置
可以为所有路由配置Http超时(响应和连接),并为每个特定路由覆盖Http超时.
### 12.1.全局超时
要配置全局http超时:
`connect-timeout`必须以毫秒为单位指定.
`response-timeout`必须指定为java.time.Duration
全局http超时示例
```yaml
spring:
cloud:
gateway:
httpclient:
connect-timeout: 1000
response-timeout: 5s
```
### 12.2.每个路由超时
要配置每个路由超时:
`connect-timeout`必须以毫秒为单位指定.
`response-timeout`必须以毫秒为单位指定.
通过配置每个路由的HTTP超时
```yaml
- id: per_route_timeouts
uri: https://example.org
predicates:
- name: Path
args:
pattern: /delay/{timeout}
metadata:
response-timeout: 200
connect-timeout: 200
```
使用Java DSL的每个路由超时配置
```java
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();
}
```
### 12.3.流利的Java Routes API
为了在Java中进行简单的配置,该`RouteLocatorBuilder`bean包含了一个流畅的API.以下清单显示了它的工作方式:
例子67. GatewaySampleApplication.java
```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`.通过使用流利的Java API,你可以使用`and()`,`or()`以及`negate()`对运营`Predicate`类.
### 12.4.DiscoveryClient路由定义定位器
您可以将网关配置为基于在`DiscoveryClient`兼容服务注册表中注册的服务来创建路由.
要启用此功能,请设置`spring.cloud.gateway.discovery.locator.enabled=true`并确保`DiscoveryClient`实现(例如Netflix Eureka,Consul或Zookeeper)在类路径上并已启用.
#### 12.4.1.DiscoveryClient路由配置谓词和过滤器
默认情况下,网关为使用所创建的路由定义单个谓词和过滤器`DiscoveryClient`.
默认谓词是使用模式定义的路径谓词`/serviceId/**`,其中`serviceId`是来自的服务ID `DiscoveryClient`.
默认过滤器是带有正则表达式`/serviceId/(?.*)`和替换的重写路径过滤器`/${remaining}`.这会在将请求发送到下游之前从路径中剥离服务ID.
如果要自定义`DiscoveryClient`路线使用的谓词或过滤器,请设置`spring.cloud.gateway.discovery.locator.predicates[x]`和`spring.cloud.gateway.discovery.locator.filters[y]`.这样做时,如果要保留该功能,则需要确保包括前面显示的默认谓词和过滤器.下面的示例显示其外观:
例子68. application.properties
```properties
spring.cloud.gateway.discovery.locator.predicates[0].name: Path
spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]: "'/'+serviceId+'/**'"
spring.cloud.gateway.discovery.locator.predicates[1].name: Host
spring.cloud.gateway.discovery.locator.predicates[1].args[pattern]: "'**.foo.com'"
spring.cloud.gateway.discovery.locator.filters[0].name: Hystrix
spring.cloud.gateway.discovery.locator.filters[0].args[name]: serviceId
spring.cloud.gateway.discovery.locator.filters[1].name: RewritePath
spring.cloud.gateway.discovery.locator.filters[1].args[regexp]: "'/' + serviceId + '/(?<remaining>.*)'"
spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'"
```
## 13. Reactor Netty访问日志
要启用Reactor Netty访问日志,请设置`-Dreactor.netty.http.server.accessLogEnabled=true`.
> 它必须是Java System属性,而不是Spring Boot属性.
您可以将日志记录系统配置为具有单独的访问日志文件.以下示例创建一个Logback配置:
例子69. logback.xml
```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行为.“全局” CORS配置是URL模式到[Spring Framework`CorsConfiguration`](https://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/cors/CorsConfiguration.html)的映射.以下示例配置了CORS:
例子70. application.yml
```yaml
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`.
## 15.执行器API
该`/gateway`驱动器的端点,您可以监视和Spring的云网关应用程序进行交互.为了可远程访问,必须在应用程序属性中[通过HTTP或JMX ](https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html#production-ready-endpoints-exposing-endpoints)[启用](https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html#production-ready-endpoints-enabling-endpoints)和[公开](https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html#production-ready-endpoints-exposing-endpoints)端点.以下清单显示了如何执行此操作:
例子71. application.properties
```properties
management.endpoint.gateway.enabled=true # default value
management.endpoints.web.exposure.include=gateway
```
### 15.1.详细执行器格式
一种新的,更详细的格式已添加到Spring Cloud Gateway.它为每个路由添加了更多详细信息,使您可以查看与每个路由关联的谓词和过滤器以及任何可用的配置.以下示例进行配置`/actuator/gateway/routes`:
```json
[
{
"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
```properties
spring.cloud.gateway.actuator.verbose.enabled=false
```
`true`在将来的版本中,它将默认为.
### 15.2.检索路由过滤器
本节详细介绍如何检索路由过滤器,包括:
- 全局过滤器
- 网关路由过滤器
#### 15.2.1.全局过滤器
要检索应用于所有路由的[全局过滤器](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#global-filters),`GET`请向发出请求`/actuator/gateway/globalfilters`.产生的响应类似于以下内容:
```json
{
"or[email protected]77856cc5": 10100,
"o[email protected]4f6fd101": 10000,
"or[email protected]32d22650": -1,
"org.springframework.cloud.gateway.filter.Forwar[email protected]": 2147483647,
"[email protected]5e0": 2147483647,
"[email protected]d23": 0,
"org.s[email protected]135064ea": 2147483637,
"[email protected]23c05889": 2147483646
}
```
该响应包含已到位的全局筛选器的详细信息.对于每个全局过滤器,都有一个过滤器对象的字符串表示形式(例如`or[email protected]77856cc5`)和过滤器链中的相应[顺序](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#gateway-combined-global-filter-and-gatewayfilter-ordering).}
#### 15.2.2.路线过滤器
要检索应用于路线的[`GatewayFilter`工厂](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#gatewayfilter-factories),`GET`请向发出请求`/actuator/gateway/routefilters`.产生的响应类似于以下内容:
```json
{
"[[email protected] configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null,
"[[email protected] configClass = Object]": null,
"[[email protected] configClass = Object]": null
}
```
该响应包含`GatewayFilter`应用于任何特定路线的工厂的详细信息.对于每个工厂,都有一个对应对象的字符串表示形式(例如`[[email protected] configClass = Object]`).请注意,该`null`值是由于端点控制器的实现不完整所致,因为它试图设置对象在过滤器链中的顺序,而该顺序不适用于`GatewayFilter`工厂对象.
### 15.3.刷新路由缓存
要清除路由缓存,`POST`请向发送请求`/actuator/gateway/refresh`.该请求返回200,但没有响应正文.
### 15.4.检索网关中定义的路由
要检索网关中定义的路由,`GET`请向发出请求`/actuator/gateway/routes`.产生的响应类似于以下内容:
```json
[{
"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
}]
```
该响应包含网关中定义的所有路由的详细信息.下表描述了响应的每个元素的结构(每个元素都是一条路线):
| 路径 | 类型 | 描述 |
| :----------------------- | :----- | :----------------------------------------------------------- |
| `route_id` | String | 路由ID. |
| `route_object.predicate` | Object | 路由谓词. |
| `route_object.filters` | Array | 该[`GatewayFilter`工厂](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#gatewayfilter-factories)使用的路由. |
| `order` | Number | 路线顺序. |
### 15.5.检索有关特定路线的信息
要检索有关一条路线的信息,`GET`请向发出请求`/actuator/gateway/routes/{id}`(例如`/actuator/gateway/routes/first_route`).产生的响应类似于以下内容:
```
{
"id": "first_route",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"/first"}
}],
"filters": [],
"uri": "https://www.uri-destination.org",
"order": 0
}]
```
下表描述了响应的结构:
| 路径 | 类型 | 描述 |
| :----------- | :----- | :--------------------------------------------------- |
| `id` | String | 路由ID. |
| `predicates` | Array | 路由谓词的集合.每个项目都定义给定谓词的名称和自变量. |
| `filters` | Array | 应用于路线的过滤器集合. |
| `uri` | String | 路由的目标URI. |
| `order` | Number | 路线顺序. |
### 15.6.创建和删除特定路线
要创建路由,`POST`请`/gateway/routes/{id_route_to_create}`使用JSON主体发出请求,以指定该路由的字段(请参阅[检索有关特定路由的信息](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/#gateway-retrieving-information-about-a-particular-route)).
要删除路线,`DELETE`请向发出请求`/gateway/routes/{id_route_to_delete}`.
### 15.7.回顾:所有端点的列表
下表列出了Spring Cloud Gateway执行器端点(请注意,每个端点都`/actuator/gateway`作为基本路径):
| ID | HTTP方法 | 描述 |
| :-------------- | :------- | :------------------------------------------- |
| `globalfilters` | 得到 | 显示应用于路由的全局过滤器列表. |
| `routefilters` | GET | 显示`GatewayFilter`应用于特定路线的工厂列表. |
| `refresh` | POST | 清除路由缓存. |
| `routes` | GET | 显示网关中定义的路由列表. |
| `routes/{id}` | GET | 显示有关特定路线的信息. |
| `routes/{id}` | POST | 将新路由添加到网关. |
| `routes/{id}` | DELETE | 从网关中删除现有路由. |
## 16.故障排除
本部分介绍使用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.窃听
反应堆的Netty `HttpClient`和`HttpServer`可具有窃听功能.与将`reactor.netty`日志级别设置为`DEBUG`或结合使用时`TRACE`,它将启用信息记录,例如通过电线发送和接收的标头和正文.要启用监听,请分别为和设置`spring.cloud.gateway.httpserver.wiretap=true`或.`spring.cloud.gateway.httpclient.wiretap=true``HttpServer``HttpClient`
## 17.开发人员指南
这些是编写网关的某些自定义组件的基本指南.
### 17.1.编写自定义路线谓词工厂
为了编写Route Predicate,您需要实现`RoutePredicateFactory`.有一个`AbstractRoutePredicateFactory`可以扩展的抽象类.
MyRoutePredicateFactory.java
```java
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<HeaderRoutePredicateFactory.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`.您可以扩展名为的抽象类`AbstractGatewayFilterFactory`.以下示例显示了如何执行此操作:
例子73. PreGatewayFilterFactory.java
```java
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(request).build());
};
}
public static class Config {
//Put the configuration properties for your filter here
}
}
```
PostGatewayFilterFactory.java
```java
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.3.编写自定义全局过滤器
要编写自定义全局过滤器,必须实现`GlobalFilter`接口.这会将过滤器应用于所有请求.
以下示例显示了如何分别设置全局前置和后置过滤器:
```java
@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.用SpringMVC或Webflux构建简单网关
> 以下描述了替代样式的网关.先前的文档均不适用于以下内容.
Spring Cloud Gateway提供了一个名为的实用程序对象`ProxyExchange`.您可以在常规的Spring Web处理程序中使用它作为方法参数.它通过镜像HTTP动词的方法支持基本的下游HTTP交换.使用MVC,它还支持通过该`forward()`方法转发到本地处理程序.要使用`ProxyExchange`,请在类路径中包含正确的模块(`spring-cloud-gateway-mvc`或`spring-cloud-gateway-webflux`).
下面的MVC示例将请求代理`/test`到远程服务器的下游:
```java
@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执行相同的操作:
```java
@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路径.例如,您可能希望提取路径的尾随元素以将它们传递到下游:
```java
@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的所有功能.结果,例如,您可以注入请求标头和查询参数,并且可以使用映射批注中的声明来约束传入的请求.有关`@RequestMapping`这些功能的更多详细信息,请参见Spring MVC中的文档.
您可以使用上的`header()`方法将标头添加到下游响应中`ProxyExchange`.
您还可以通过向`get()`方法(和其他方法)添加映射器来操纵响应头(以及响应中您喜欢的其他任何东西).映射器是一个`Function`接受传入的对象`ResponseEntity`,并将其转换为传出的对象.
对不传递到下游的“敏感”标头(默认情况下为`cookie`和`authorization`)和“ proxy”(`x-forwarded-*`)标头提供了一流的支持.
## 19.配置属性
要查看所有与Spring Cloud Gateway相关的配置属性的列表,请参阅[附录](https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/appendix.html).
## 附录A:常见的应用程序属性
可以在`application.properties`文件内部`application.yml`,文件内部或命令行开关中指定各种属性.本附录提供了常见的Spring Cloud Gateway属性列表以及对使用它们的基础类的引用.
> 属性贡献可以来自类路径上的其他jar文件,因此您不应将其视为详尽的列表.另外,您可以定义自己的属性.
>
> 这些属性都具有spring.cloud.gateway前缀
| 名称 | 默认 | 描述 |
| :--------------------------------------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- |
| .default-filters | | 应用于每个路由的过滤器定义列表. |
| .discovery.locator.enabled | false | 启用DiscoveryClient网关集成的标志. |
| .discovery.locator.filters | | |
| .discovery.locator.include-expression | true | 将评估是否在网关集成中包括服务的SpEL表达式,默认为:true. |
| .discovery.locator.lower-case-service-id | false | 谓词和过滤器中的小写serviceId选项,默认为false.当eureka自动将serviceId大写时,对它有用.因此MYSERIVCE将与/ myservice / **匹配 |
| .discovery.locator.predicates | | |
| .discovery.locator.route-id-prefix | | routeId的前缀,默认为DiscoveryClient.getClass().getSimpleName()+“ _”.服务ID将被添加以创建routeId. |
| .discovery.locator.url-expression | 'lb://'+ serviceId | 为每个路线创建uri的SpEL表达式,默认为:'lb://'+ serviceId. |
| .enabled | true | 启用网关功能. |
| .filter.remove-hop-by-hop.headers | | |
| .filter.remove-hop-by-hop.order | | |
| .filter.request-rate-limiter.deny-empty-key | true | 如果**解析器返回空**,则切换为拒绝请求,默认为true. |
| .filter.request-rate-limiter.empty-key-status-code | | denyEmptyKey为true时返回的HttpStatus,默认为FORBIDDEN. |
| .filter.secure-headers.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' | |
| .filter.secure-headers.content-type-options | Nosniff | |
| .filter.secure-headers.disable | | |
| .filter.secure-headers.download-options | noopen | |
| .filter.secure-headers.frame-options | DENY | |
| .filter.secure-headers.permited-cross-domain-policies | none | |
| spring.cloud.gateway.filter.secure-headers.referrer-policy | no-referrer | |
| .filter.secure-headers.strict-transport-security | max-age=631138519 | |
| .filter.secure-headers.xss-protection-header | 1 ; mode=block | |
| .forwarded.enabled | true | 启用ForwardedHeadersFilter. |
| .globalcors.add-to-simple-url-handler-mapping | false | 是否将全局CORS配置添加到URL处理程序. |
| .globalcors.cors-configuration | | |
| .httpclient.connect-timeout | | 连接超时(以毫秒为单位),默认值为45s. |
| .httpclient.pool.acquire-timeout | | 仅对于FIXED类型,等待等待的最长时间(以毫秒为单位). |
| .httpclient.pool.max-connections | | 仅对于FIXED类型,是在现有连接上开始挂起获取之前的最大连接数. |
| .httpclient.pool.max-idle-time | | 以毫秒为单位的时间,之后通道将被关闭.如果为NULL,则没有最大空闲时间. |
| .httpclient.pool.max-life-time | | 通道将关闭的持续时间.如果为NULL,则没有最大寿命. |
| .httpclient.pool.name | 代理 | 通道池映射名称,默认为代理. |
| .httpclient.pool.type | | 供HttpClient使用的池的类型,默认为ELASTIC. |
| .httpclient.proxy.host | | Netty HttpClient代理配置的主机名. |
| .httpclient.proxy.non-proxy-hosts-pattern | | 配置的主机列表的正则表达式(Java).应该直接到达,绕过代理 |
| .httpclient.proxy.password | | Netty HttpClient代理配置的密码. |
| .httpclient.proxy.port | | Netty HttpClient代理配置的端口. |
| .httpclient.proxy.username | | Netty HttpClient代理配置的用户名. |
| .httpclient.response-timeout | | 响应超时. |
| .httpclient.ssl.close-notify-flush-timeout | 3000ms | SSL close_notify刷新超时.默认为3000毫秒 |
| .httpclient.ssl.close-notify-flush-timeout-millis | | |
| .httpclient.ssl.close-notify-read-timeout | | SSL close_notify读取超时.默认为0毫秒. |
| .httpclient.ssl.close-notify-read-timeout-millis | | |
| .httpclient.ssl.default-configuration-type | | 缺省的ssl配置类型.默认为TCP. |
| .httpclient.ssl.handshake-timeout | 10000毫秒 | SSL握手超时.默认为10000毫秒 |
| .httpclient.ssl.handshake-timeout-millis | | |
| .httpclient.ssl.key-password | | **密码,默认与keyStorePassword相同. |
| .httpclient.ssl.key-store | | Netty HttpClient的**库路径. |
| .httpclient.ssl.key-store-password | | **库密码. |
| .httpclient.ssl.key-store-provider | | Netty HttpClient的**库提供程序,可选字段. |
| .httpclient.ssl.key-store-type | JKS | Netty HttpClient的**库类型,默认为JKS. |
| .httpclient.ssl.trusted-x509-certificates | | 用于验证远程端点的证书的受信任证书. |
| .httpclient.ssl.use-insecure-trust-manager | false | 安装netty InsecureTrustManagerFactory.这是不安全的,不适合生产. |
| .httpclient.websocket.max-frame-payload-length | | 最大帧有效负载长度. |
| .httpclient.wiretap | false | 为Netty HttpClient启用窃听调试. |
| .httpserver.wiretap | false | 为Netty HttpServer启用窃听调试. |
| .loadbalancer.use404 | false | |
| .metrics.enabled | true | 启用指标数据收集. |
| .metrics.tags | | 标签映射添加到指标. |
| .redis-rate-limiter.burst-capacity-header | X-RateLimit-Burst-Capacity | 返回突发容量配置的标头名称. |
| .redis-rate-limiter.config | | |
| .redis-rate-limiter.include-headers | true | 是否包括包含速率限制器信息的标头,默认为true. |
| .redis-rate-limiter.remaining-header | X-RateLimit-Remaining | 标头名称,用于返回当前秒内剩余请求数. |
| .redis-rate-limiter.replenish-rate-header | X-RateLimit-Replenish-Rate | 返回补充费率配置的标头名称. |
| .routes | | 路线清单. |
| .set-status.original-status-header-name | | 标头名称,其中包含代理请求的http代码. |
| .streaming-media-types | | |
| .x-forwarded.enabled | true | 启用了XForwardedHeadersFilter. |
| .x-forwarded.append | true | 启用了将X-Forwarded-For作为列表附加. |
| .x-forwarded.for-enabled | true | 启用了X-Forwarded-For. |
| .x-forwarded.host-append | true | 启用了将X-Forwarded-Host作为列表追加. |
| .x-forwarded.host-enabled | true | 启用了X-Forwarded-Host. |
| .x-forwarded.order | 0 | XForwardedHeadersFilter的顺序. |
| .x-forwarded.port-append | true | 启用了将X-Forwarded-Port作为列表追加. |
| .x-forwarded.port-enabled | true | 启用了X-Forwarded-Port. |
| .x-forwarded.prefix-append | true | 启用将X-Forwarded-Prefix作为列表追加. |
| .x-forwarded.prefix-enabled | true | 启用了X-Forwarded-Prefix. |
| .x-forwarded.proto-append | true | 启用将X-Forwarded-Proto作为列表附加. |
| .x-forwarded.proto-enabled | true | 启用了X-Forwarded-Proto. |