spring cloud 之Gateway使用详解

spring cloud 之Gateway使用详解,从零开始搭建Gateway,进行自定义配置,主要文档内容来源与spring cloud官方文档

Posted by yishuifengxiao on 2019-08-20

Spring Cloud Gateway 是 Spring Cloud 官方推出的第二代网关框架,取代 Zuul 网关。网关作为流量的,在微服务系统中有着非常作用,网关常见的功能有路由转发、权限校验、限流控制等作用。

Spring Cloud Gateway 基于 Spring Boot 2.0, Spring WebFlux 和 Project Reactor 构建。因此,许多熟悉的同步库(例如 Spring Data 和 Spring Security)和模式在使用 Spring Cloud Gateway 时可能不适用.

Spring Cloud Gateway 需要 Spring Boot 和 Spring Webflux 提供的 Netty 运行时。 它不能在传统的 Servlet 容器中工作或构建为 WAR。

一 快速入门

在使用 gateway 之前,需要先明确几个概念

  • Route: 路由是网关的基本构建块。 它由 ID,目标 URI,Predicate 集合和 Filter 集合组成。 如果 Predicate 的结果为真,则匹配路由。
  • Predicate: 这是一个 Java 8 中的Predicate函数。 输入类型是 Spring 框架中的ServerWebExchange。 这允许开发人员匹配来自 HTTP 请求的任何内容,例如请求头或参数。
  • Filter :这些是使用特定工厂构建的 Spring 框架里的GatewayFilter实例。 这里,可以在发送下游请求之前或之后修改请求和响应。

客户端向 Spring Cloud Gateway 发出请求,如果该请求与网关中的路由匹配, ,则将其转发到网关中对应的 Web 处理程序,然后这些请求会被特定的过滤器链处理。

1.1 加入依赖

新建一个 spring cloud 项目,在项目的 pom 文件里加入以下依赖

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

1.2 配置属性

在属性配置文件里加入以下配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server:
port: 8081

spring:
application:
name: gateway-demo
cloud:
gateway:
discovery:
locator:
enabled: true
lowerCaseServiceId: true

eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/

spring.cloud.gateway.discovery.locator.enabledtrue表明 gateway 开启服务注册和发现的功能,spring cloud gateway 自动根据发现的服务为每一个服务创建了一个 router,这个 router 将以服务名开头的请求路径转发到对应的服务。

spring.cloud.gateway.discovery.locator.lowerCaseServiceId是将请求路径上的服务名配置为小写(因为服务注册的时候,向注册中心注册时将服务名转成大写的了)

1.3 自定义路由

在默认情况下,向网关发送的请求时,url 必须带上服务名service-demo这个前缀,才能转发到service-demo上,网关会在转发之前会将service-demo去掉。

如果有时候因为项目需求需要自定义转发路径,我们设置自己的转发规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
spring:
application:
name: gateway-demo
cloud:
gateway:
discovery:
locator:
enabled: false
lowerCaseServiceId: true
routes:
- id: service-demo
uri: lb://SERVICE-DEMO
predicates:
- Path=/demo/**
filters:
- StripPrefix=1

在上面的配置中,网关会将以/demo/**开头的请求都会转发到 uri 为lb://SERVICE-DEMO的地址上,其中lb://SERVICE-DEMOservice-demo服务的负载均衡地址,并用StripPrefixfilter 在转发之前将/demo去掉。

spring.cloud.gateway.discovery.locator.enabled=false关闭自动发现功能,如果不改的话,网关就会为每个服务创建两个路由,之前的localhost:8081/service-demo/hi?name=1323这样的请求地址也能正常访问。

二 路由匹配

Spring Cloud Gateway 将路由作为 Spring WebFlux 的 HandlerMapping基础结构的一部分进行匹配。 Spring Cloud Gateway 包含许多基于 HTTP 请求的不同属性进行匹配的内置的 Route Predicate 工厂,多个 Predicate 工厂可以通过 与连接 进行组合。

2.1 After Route Predicate

After Route Predicate,可配置一个时间,当请求的时间在配置时间之后,才交给 router 去处理

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]

2.2 Before Route Predicate

Before Route Predicate,可配置一个时间,当请求的时间在配置时间之前,才交给 router 去处理

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: before_route
uri: https://example.org
predicates:
- Before=2017-01-20T17:42:47.789-07:00[America/Denver]

2.3 Between Route Predicate

Between Route Predicate,可配置两个时间,当请求的时间在配置时间之间,才交给 router 去处理

1
2
3
4
5
6
7
8
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]

Cookie Route Predicate Factory 有两个参数,cookie 名称和正则表达式。 此 Predicate 匹配具有给定名称且值与正则表达式匹配的 cookie。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p

此路由匹配请求有一个名为 chocolate 的 cookie,其值与 ch.p 正则表达式匹配。

2.5 Header Route Predicate

Header Route Predicate 工厂采用两个参数,请求头名称和正则表达式。 此 Predicate 与具有给定名称且值与正则表达式匹配的请求头匹配。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://example.org
predicates:
- Header=X-Request-Id, \d+

如果请求具有名为 X-Request-Id 的请求头,则该路由匹配,其值与\d+正则表达式匹配(具有一个或多个数字的值)

2.6 Host Route Predicate

Host Route Predicate Factory 采用一个参数:多个主机名匹配规则。 该匹配模式是一种. 作为分隔符,采用 Ant 风格匹配。 此 Predicate 匹配与模式匹配的 Host 请求头。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Host=**.somehost.org,**.anotherhost.org

也支持 URI 模板变量,例如{sub}.myhost.org

如果请求的主机头具有值www.somehost.orgbeta.somehost.orgwww.anotherhost.org,则将匹配此路由。

此 Predicate 将 URI 模板变量(如上例中定义的 sub)提取为名称和值的映射,可以根据键ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTEServerWebExchange.getAttributes()中获取其中的值,也可以在GatewayFilter Factories使用这些值。

2.7 Method Route Predicate

Method Route Predicate Factory 采用一个参数:要匹配的 HTTP 方法。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET

如果请求方法是 GET,则此路由将匹配。

2.8 Path Route Predicate

Path Route Predicate Factory 有两个参数:多个的 Spring PathMatcher匹配规则和可选的matchOptionalTrailingSeparator标志。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Path=/foo/{segment},/bar/{segment}

则此路由将匹配例如:/foo/1/foo/bar/bar/baz形式的路径。

此 Predicate 将 URI 模板变量(如上例中定义的segment)提取为名称和值的映射,并将其放在ServerWebExchange.getAttributes()中,根据键ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE从中获取对应的值,也可以在GatewayFilter Factories使用这些值。

可以使用实用程序方法来更轻松地访问这些变量,调用方法如下。

1
2
3
Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);

String segment = uriVariables.get("segment");

2.9 Query Route Predicate

Query Route Predicate Factory 有两个参数:一个必需的参数和一个可选的正则表达式。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=baz

如果请求包含 baz 查询参数,则此路由将匹配。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=foo, ba.

如果请求包含其值与 ba 匹配的 foo 查询参数,则此路由将匹配。 regexp,所以 bar 和 baz 匹配。

2.10 RemoteAddr Route Predicate

RemoteAddr Route Predicate Factory 采用 CIDR 表示法(IPv4 或 IPv6)字符串的列表(最小值为 1),例如, 192.168.0.1/16(其中 192.168.0.1 是 IP 地址,16 是子网掩码)。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: https://example.org
predicates:
- RemoteAddr=192.168.1.1/24

如果请求的远程地址是例如 192.168.1.10,则此路由将匹配。

修改远程地址的解析方式
默认情况下,RemoteAddr Route Predicate Factory 使用传入请求中的远程地址。如果 Spring Cloud Gateway 位于代理层后面,则可能与实际客户端 IP 地址不匹配。

您可以通过设置自定义RemoteAddressResolver来自定义解析远程地址的方式。 Spring Cloud Gateway 附带一个基于X-Forwarded-For请求头的非默认远程地址解析器XForwardedRemoteAddressResolver

XForwardedRemoteAddressResolver有两个静态构造函数方法,它们采用不同的安全方法:

XForwardedRemoteAddressResolver::trustAll返回一个RemoteAddressResolver,它始终采用X-Forwarded-For请求头中找到的第一个 IP 地址。这种方法容易受到欺骗,因为恶意客户端可以为解析器接受的X-Forwarded-For设置初始值。

XForwardedRemoteAddressResolver::maxTrustedIndex采用与 Spring Cloud Gateway 前运行的可信基础架构数相关的索引。例如,如果只能通过 HAProxy 访问 Spring Cloud Gateway,则应使用值 1。如果在可访问 Spring Cloud Gateway 之前需要两跳可信基础架构,则应使用值 2。

三 网关过滤器

路由过滤器范围限定为特定路径,它允许以某种方式修改传入的 HTTP 请求或传出的 HTTP 响应。 Spring Cloud Gateway 包含许多内置的 GatewayFilter 工厂。

注意有关如何使用以下任何过滤器的更详细示例,请查看单元测试。

3.1 AddRequestHeader

AddRequestHeader GatewayFilter 工厂接受一个名称和值参数。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
filters:
- AddRequestHeader=X-Request-Foo, Bar

这将为所有匹配请求的下游请求头添加 X-Request-Foo:Bar 请求头。

3.2 AddRequestParameter

AddRequestParameter GatewayFilter Factory 采用名称和值参数。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: https://example.org
filters:
- AddRequestParameter=foo, bar

这会将foo=bar添加到下游请求的所有匹配请求的查询字符串中。

3.3 AddResponseHeader

AddResponseHeader GatewayFilter Factory 采用名称和值参数。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: add_response_header_route
uri: https://example.org
filters:
- AddResponseHeader=X-Response-Foo, Bar

这会将X-Response-Foo:Bar请求头添加到所有匹配请求的下游响应标头中。

3.4 DedupeResponseHeader

DedupeResponseHeader GatewayFilter Factory 采用名称参数和可选策略参数。 name 可以包含标题名称列表,空格分隔。

1
2
3
4
5
6
7
8
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-CredentialsAccess-Control-Allow-Origin响应头的重复值。

DedupeResponseHeader 过滤器还接受可选的策略参数。 接受的值为RETAIN_FIRST(默认值),RETAIN_LASTRETAIN_UNIQUE

3.5 Hystrix

Hystrix 是一个实现了断路器模式的 Netflix 库。 Hystrix GatewayFilter 允许您将断路器引入网关路由,保护您的服务免受级联故障的影响,并允许您在下游故障时提供回退响应。

要在项目中启用 Hystrix GatewayFilters,请在 Spring Cloud Netflix 上添加spring-cloud-starter-netflix-hystrix的依赖。

Hystrix GatewayFilter Factory 需要单个名称参数,该参数是HystrixCommand的名称。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: hystrix_route
uri: https://example.org
filters:
- Hystrix=myCommandName

这将使用一个名为 myCommandName 的HystrixCommand

Hystrix 过滤器还可以接受可选的fallbackUri参数,fallbackUri参数目前仅支持forward:schemed URIs。 如果调用了回退,则请求将被转发到与 URI 匹配的控制器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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

当调用 Hystrix 后备时,这将转发到/incaseoffailureuset这个 URI。 请注意,此示例还通过目标 URI 上可选的 lb 前缀实现负载平衡。

主要方案是将 fallbackUri 用于网关应用程序内的内部控制器或处理程序。 但是,也可以将请求重新路由到外部应用程序中的控制器或处理程序,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

在此示例中,网关应用程序中没有设置回退端点或处理程序,但是在http//localhost:9994下注册的另一个应用程序中进行处理。

如果请求被转发到回退,Hystrix 网关过滤器还会提供导致它的Throwable,并以键名 ServerWebExchangeUtils.HYSTRIX_EXECUTION_EXCEPTION_ATTR存储在ServerWebExchange中,从而处理网关应用程序中的回退时使用该属性。

对于外部控制器/处理程序方案,可以添加包含异常详细信息的请求头。 您可以在 FallbackHeaders GatewayFilter Factory 部分中找到有关它的更多信息。

Hystrix 设置(例如超时)可以使用全局默认值配置,也可以使用应用程序属性逐个路径配置。

要为上面的示例路由设置 5 秒超时,将使用以下配置:

1
hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds: 5000

3.6 FallbackHeaders

FallbackHeaders 工厂允许您在转发到外部应用程序中的 fallbackUri 的请求头中添加 Hystrix 执行异常详细信息,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
filters:
- name: FallbackHeaders
args:
executionExceptionTypeHeaderName: Test-Header

在此示例中,在运行 HystrixCommand 时发生执行异常后,会将请求转发到在localhost:9994上运行的应用程序中的回退端点或处理程序。 导致异常的异常类型消息和-if available- root的请求头会由 FallbackHeaders 过滤器添加到该请求的请求头中。

通过设置下面列出的参数的值及其默认值,可以在配置中覆盖标头的名称:

1
2
3
4
- executionExceptionTypeHeaderName ("Execution-Exception-Type")
- executionExceptionMessageHeaderName ("Execution-Exception-Message")
- rootCauseExceptionTypeHeaderName ("Root-Cause-Exception-Type")
- rootCauseExceptionMessageHeaderName ("Root-Cause-Exception-Message")

3.7 PrefixPath

PrefixPath GatewayFilter Factory 采用单个前缀参数。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- PrefixPath=/mypath

这将匹配到所有以/mypath前缀的路径,并将请求/hello转发到/mypath/hello

3.8 PreserveHostHeader

PreserveHostHeader GatewayFilter Factory 没有参数。 此过滤器设置路由过滤器将检查的请求属性,以确定是否应发送原始主机头,而不是 http 客户端确定的主机头。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: preserve_host_route
uri: https://example.org
filters:
- PreserveHostHeader

3.9 RequestRateLimiter

RequestRateLimiter GatewayFilter Factory 使用RateLimiter实现来确定是否允许当前请求继续。 如果不是,则返回 HTTP 429 - Too Many Requests(默认情况下)的状态。

此过滤器采用可选的keyResolver参数和特定于速率限制器的参数(参见下文)。

keyResolver是一个实现KeyResolver接口的 bean。 在配置中使用 SpEL 按名称引用 bean。例如 #{@ myKeyResolver}是一个引用名为myKeyResolver的 bean 的 SpEL 表达式。

1
2
3
public interface KeyResolver {
Mono<String> resolve(ServerWebExchange exchange);
}

PrincipalNameKeyResolverKeyResolver的一个默认实现,它从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 不能通过“快捷方式”表示法进行配置。 以下示例无效

1
2
# INVALID SHORTCUT CONFIGURATION
spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2, #{@userkeyresolver}

Redis RateLimiter

这个 redis 扩展在 Stripe 基础上基于令牌桶算法完成的实现,它需要项目引入spring-boot-starter-data-redis-reactive 启动器。

redis-rate-limiter.replenishRate表示希望允许用户每秒执行多少请求,而不会丢弃任何请求。 这是令牌桶填充的速率。

redis-rate-limiter.burstCapacity是用户在一秒钟内允许执行的最大请求数。 这是令牌桶可以容纳的令牌数。 将此值设置为零将阻止所有请求。

可以通过在replenishRateburstCapacity中设置相同的值来实现稳定的速率,也可以通过将burstCapacity设置为高于replenishRate来允许临时突发。 在这种情况下,需要在突发之间根据replenishRate允许速率限制器一段时间,因为连续 2 次突发将导致请求被丢弃(HTTP 429 - Too Many Requests)。

配置数据

1
2
3
4
5
6
7
8
9
10
11
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

java 代码

1
2
3
4
@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}

这定义了每个用户 10 的请求率限制。 允许突发 20,但下一秒只有 10 个请求可用。 KeyResolver是一个简单的获取用户请求参数(注意:这不建议用于生产)。

速率限制器也可以使用实现RateLimiter接口的 bean 来定义, 在配置中使用 SpEL 按名称引用 bean。 #{@ myRateLimiter}是一个引用名为myRateLimiter的 bean 的 SpEL 表达式。

1
2
3
4
5
6
7
8
9
10
11
spring:
cloud:
gateway:
routes:
- id: requestratelimiter_route
uri: https://example.org
filters:
- name: RequestRateLimiter
args:
rate-limiter: "#{@myRateLimiter}"
key-resolver: "#{@userKeyResolver}"

3.10 RedirectTo

RedirectTo GatewayFilter Factory 采用statusurl参数。 状态应该是 300 系列重定向 http 代码,例如 301. url 应该是有效的 URL。 这将是 Location 标头的值。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- RedirectTo=302, https://acme.org

这将发送状态 302,其中包含Location:https://acme.org标头以执行重定向。

3.11 RemoveHopByHopHeaders

RemoveHopByHopHeadersFilter GatewayFilter Factory 从转发的请求中删除标头。 删除的标头列表来自 IETF。

默认删除的请求头是:

  • Connection
  • Keep-Alive
  • Proxy-Authenticate
  • Proxy-Authorization
  • TE
  • Trailer
  • Transfer-Encoding
  • Upgrade

要更改此设置,请将spring.cloud.gateway.filter.remove-non-proxy-headers.headers属性设置为要删除的请求头名称列表。

3.12 RemoveRequestHeader

RemoveRequestHeader GatewayFilter Factory 采用名称参数。 它的值是要删除的请求头的名称。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: removerequestheader_route
uri: https://example.org
filters:
- RemoveRequestHeader=X-Request-Foo

这将在向下游发送之前删除X-Request-Foo请求头。

3.13 RemoveResponseHeader

RemoveResponseHeader GatewayFilter Factory 采用名称参数。 它是要删除的标头的名称。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: removeresponseheader_route
uri: https://example.org
filters:
- RemoveResponseHeader=X-Response-Foo

这将在响应返回到网关客户端之前从响应中删除X-Response-Foo标头。

要删除任何类型的敏感标头,您应该为您可能要执行此操作的任何路由配置此过滤器。 此外,您可以使用spring.cloud.gateway.default-filters配置此过滤器并将其应用于所有路由 z 中。

3.14 RewritePath

RewritePath GatewayFilter Factory 采用路径正则参数和替换参数。 这使用 Java 正则表达式来灵活地重写请求路径。

1
2
3
4
5
6
7
8
9
10
spring:
cloud:
gateway:
routes:
- id: rewritepath_route
uri: https://example.org
predicates:
- Path=/foo/**
filters:
- RewritePath=/foo/(?<segment>.*), /$\{segment}

对于/foo/bar的请求路径,这将在发出下游请求之前将路径设置为/bar。 注意由于 YAML 规范,$替换为$\

3.15 RewriteResponseHeader

RewriteResponseHeader GatewayFilter Factory 采用名称,正则表达式和替换参数。 它使用 Java 正则表达式以灵活的方式重写响应头值。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: rewriteresponseheader_route
uri: https://example.org
filters:
- RewriteResponseHeader=X-Response-Foo, , password=[^&]+, password=***

对于标题值/42?user=ford&password=omg!what&flag=rue,在发出下游请求后,它将被设置为/42?user=ford&password=***&flag=true。 由于 YAML 规范,请使用

3.16 SaveSession

SaveSession GatewayFilter Factory 在转发下游调用之前强制执行WebSession::save操作。 当使用 Spring Session 与懒加载数据之类的东西时需要确保在转发调用之前已保存会话状态。

1
2
3
4
5
6
7
8
9
10
spring:
cloud:
gateway:
routes:
- id: save_session
uri: https://example.org
predicates:
- Path=/foo/**
filters:
- SaveSession

如果要将 Spring Security 与 Spring Session 集成并且希望确保将安全性详细信息转发到远程进程,则这个配置很关键。

3.17 SecureHeaders

SecureHeaders GatewayFilter Factory 为响应添加了许多标头。

添加以下标头(以及默认值):

1
2
3
4
5
6
7
8
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设置相应的属性:

1
2
3
4
5
6
7
8
xss-protection-header
strict-transport-security
frame-options
content-type-options
referrer-policy
content-security-policy
download-options
permitted-cross-domain-policies

要禁用默认值,请使用逗号分隔值设置属性spring.cloud.gateway.filter.secure-headers.disable

示例:spring.cloud.gateway.filter.secure-headers.disable = frame-options,download-options

3.18 SetPath

SetPath GatewayFilter Factory 采用路径模板参数。 它提供了一种通过允许模板化路径段来操作请求路径的简单方法。 这使用了 Spring Framework 中的 uri 模板,允许多个匹配的段。

1
2
3
4
5
6
7
8
9
10
spring:
cloud:
gateway:
routes:
- id: setpath_route
uri: https://example.org
predicates:
- Path=/foo/{segment}
filters:
- SetPath=/{segment}

对于/foo/bar的请求路径,这将在发出下游请求之前将路径设置为/bar

3.19 SetResponseHeader

SetResponseHeader GatewayFilter Factory 获取名称和值参数。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: setresponseheader_route
uri: https://example.org
filters:
- SetResponseHeader=X-Response-Foo, Bar

此 GatewayFilter 用给定名称替换所有标头,而不是添加。 因此,如果下游服务器包含X-Response-Foo:1234响应,则将替换为X-Response-Foo:Bar,这是网关客户端将接收的内容。

3.20 SetStatus

SetStatus GatewayFilter Factory 采用单个状态参数。 它必须是有效的HttpStatus, 它可以是整数值 404 或 NOT_FOUND 的枚举字符串表示形式。

1
2
3
4
5
6
7
8
9
10
11
12
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。

3.21 StripPrefix

StripPrefix GatewayFilter Factory 采用一个参数,即部件。 parts 参数指示在向下游发送之前从请求中剥离的路径中的部分数。

1
2
3
4
5
6
7
8
9
10
spring:
cloud:
gateway:
routes:
- id: nameRoot
uri: http://nameservice
predicates:
- Path=/name/**
filters:
- StripPrefix=2

当通过网关向/name/bar/foo发出请求时,对nameservice的请求将转发到http//nameservice/foo

3.22 Retry

Retry GatewayFilter Factory 将重试,状态,方法和系列作为参数。

  • retries:应尝试的重试次数
  • statuses:应该重试的 HTTP 状态代码,使用org.springframework.http.HttpStatus表示
  • methods:应该重试的 HTTP 方法,使用org.springframework.http.HttpMethod表示
  • series:要重试的一系列状态代码,使用org.springframework.http.HttpStatus.Series表示
1
2
3
4
5
6
7
8
9
10
11
12
13
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

重试过滤器当前不支持使用正文重试(例如,对于具有正文的 POST 或 PUT 请求)。

当使用带有转发前缀 URL 的重试过滤器时,应仔细编写目标端点,以便在出现错误时不会执行任何可能导致响应发送到客户端并提交的操作。 例如,如果目标端点是带注释的控制器,则目标控制器方法不应返回带有错误状态代码的 ResponseEntity。 相反,它应抛出异常或发出错误信号,例如 通过Mono.error(ex)返回值,可以将重试过滤器配置为通过重试来处理。

3.23 RequestSize

当请求大小大于允许的限制时,RequestSize GatewayFilter Factory 可以限制请求到达下游服务。 过滤器将RequestSize作为参数,该参数是以字节为单位定义的请求的允许大小限制。

1
2
3
4
5
6
7
8
9
10
11
12
spring:
cloud:
gateway:
routes:
- id: request_size_route
uri: http://localhost:8080/upload
predicates:
- Path=/upload
filters:
- name: RequestSize
args:
maxSize: 5000000

当请求因大小而被拒绝时,RequestSize GatewayFilter Factory 将响应状态设置为 413 Payload Too Large,并附加标头 errorMessage。 以下是这样的一个例子

1
errorMessage : Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB

如果未在路由定义中提供过滤器参数,则默认请求大小将设置为 5 MB。

3.24 ModifyRequestBody

此过滤器被视为 BETA,API 可能在将来发生变化

此过滤器可用于在网关向下游发送请求主体之前对其进行修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@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;
}
}

3.25 ModifyResponseBody

此过滤器被视为 BETA,API 可能在将来发生变化

此过滤器可用于在将响应主体发送回客户端之前对其进行修改。

1
2
3
4
5
6
7
8
9
@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();
}

3.26 Default Filters

如果您想添加过滤器并将其应用于所有路线,可以使用 spring.cloud.gateway.default-filters。 此属性采用过滤器列表

1
2
3
4
5
6
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Foo, Default-Bar
- PrefixPath=/httpbin

四 全局过滤器

GlobalFilter 接口与 GatewayFilter 具有相同的签名, 这些是有条件地应用于所有路线的特殊过滤器。 (此接口和用法可能会在未来的里程碑中发生变化)。

4.1 过滤器排序

当请求进入(并匹配路由)时,Filtering Web Handler 会将 GlobalFilter 的所有实例和 GatewayFilter 的所有路由特定实例添加到过滤器链。 这个组合的过滤器链由org.springframework.core.Ordered接口排序,可以通过实现getOrder()方法或使用@Order注释来设置。

由于 Spring Cloud Gateway 区分了过滤器逻辑执行的“前”和“后”阶段,第一个前置过滤器和最后一个后置过滤器具有最高优先级。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Bean
@Order(-1)
public GlobalFilter a() {
return (exchange, chain) -> {
log.info("first pre filter");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("third post filter");
}));
};
}

@Bean
@Order(0)
public GlobalFilter b() {
return (exchange, chain) -> {
log.info("second pre filter");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("second post filter");
}));
};
}

@Bean
@Order(1)
public GlobalFilter c() {
return (exchange, chain) -> {
log.info("third pre filter");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("first post filter");
}));
};
}

4.2 Forward Routing Filter

ForwardRoutingFilter使用键ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR从 exchange 中查找 URI。 如果 url 具有 forward 方案(即forward:///localendpoint),它将使用 Spring DispatcherHandler 处理请求。 请求 URL 的路径部分将被转发 URL 中的路径覆盖。 未修改的原始 URL 将追加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR属性中的列表中。

4.3 LoadBalancerClient Filter

LoadBalancerClientFilter 使用键ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR从 exchange 中查找 URI。 如果 url 具有 lb 方案(即lb//myservice),它将使用 Spring Cloud LoadBalancerClient 将名称(前一示例中的 myservice)解析为实际主机和端口,并替换相同属性中的 URI。 未修改的原始 URL 将追加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR属性中的列表中。 过滤器还将查看ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR属性以查看它是否等于 lb,然后应用相同的规则。

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: myRoute
uri: lb://service
predicates:
- Path=/service/**

默认情况下,在 LoadBalancer 中找不到服务实例时,将返回 503。 您可以通过设置 spring.cloud.gateway.loadbalancer.use404 = true 来配置网关以返回 404。

从 LoadBalancer 返回的ServiceInstanceisSecure值将覆盖在对网关发出的请求中指定的方案。 例如,如果请求通过 HTTPS 进入网关但ServiceInstance指示它不安全,则下游请求将通过 HTTP 进行。 相反的情况也适用。 但是,如果为网关配置中的路由指定了GATEWAY_SCHEME_PREFIX_ATTR,则将剥离前缀,并且路由 URL 中的结果方案将覆盖ServiceInstance配置。

4.4 Netty Routing Filter

如果位于ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR交换属性中的 URL 具有 http 或 https 方案,则运行 Netty 路由过滤器。 它使用 Netty HttpClient 发出下游代理请求。 响应放在ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR交换属性中,以便在以后的过滤器中使用。 (有一个实验性的 WebClientHttpRoutingFilter 执行相同的功能,但不需要 netty)

4.5 Netty Write Response Filter

如果ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR交换属性中存在 Netty HttpClientResponse,则运行NettyWriteResponseFilter。 它在所有其他过滤器完成后运行,并将代理响应写回网关客户端响应。 (有一个实验性的 WebClientWriteResponseFilter 执行相同的功能,但不需要 netty)

4.6 RouteToRequestUrl Filter

如果ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR交换属性中存在 Route 对象,则运行 RouteToRequestUrlFilter。 它根据请求 URI 创建一个新 URI,但使用 Route 对象的 URI 属性进行更新。 新 URI 放在ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR交换属性`中。

如果 URI 具有方案前缀,例如lb:ws:// serviceid,则 lb 方案将从 URI 中剥离并放置在ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR中,以便稍后在过滤器链中使用。

4.7 Websocket Routing Filter

如果位于ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR交换属性中的 URL 具有 ws 或 wss 方案,则运行 Websocket 路由过滤器。 它使用 Spring Web Socket 基础结构将 Websocket 请求转发到下游。

可以通过在 URI 前面添加 lb 来对 Websockets 进行负载平衡,例如lb:ws//serviceid

如果您使用 SockJS 作为普通 http 的后备,则应配置正常的 HTTP 路由以及 Websocket 路由。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
spring:
cloud:
gateway:
routes:
# SockJS route
- id: websocket_sockjs_route
uri: http://localhost:3001
predicates:
- Path=/websocket/info/**
# Normwal Websocket route
- id: websocket_route
uri: ws://localhost:3001
predicates:
- Path=/websocket/**

4.8 Gateway Metrics Filter

要启用 Gateway Metrics,请将spring-boot-starter-actuator添加为项目依赖项。 然后,默认情况下,只要属性spring.cloud.gateway.metrics.enabled未设置为false,网关指标筛选器就会运行。 此过滤器添加名为“gateway.requests”的计时器度量标准,其中包含以下标记:

1
2
3
4
5
6
routeId:路由ID
routeUri:API将路由到的URI
outcome:由HttpStatus.Series分类的结果
status:Http返回给客户端的请求状态
httpStatusCode:返回给客户端的请求的Http状态
httpMethod:用于请求的Http方法

然后可以从/actuator/metrics/gateway.requests中删除这些指标,并可以轻松地与Prometheus集成以创建 Grafana 仪表板。

要启用 pometheus 端点,请将 micrometer-registry-prometheus 添加为项目依赖项。

4.9 Marking An Exchange As Routed

在 Gateway 路由了ServerWebExchange之后,它会通过将gatewayAlreadyRouted添加到exchange属性来将该交换标记为“路由”。 一旦请求被标记为路由,其他路由过滤器将不会再次路由请求,实质上是跳过过滤器。 您可以使用便捷方法将交换标记为路由,或检查交换是否已路由。

ServerWebExchangeUtils.isAlreadyRouted接受ServerWebExchange对象并检查它是否已“路由”
ServerWebExchangeUtils.setAlreadyRouted接受ServerWebExchange对象并将其标记为“路由”

5 进阶配置

Spring Cloud Gateway 的配置由RouteDefinitionLocators 的集合驱动。

1
2
3
public interface RouteDefinitionLocator {
Flux<RouteDefinition> getRouteDefinitions();
}

默认情况下,PropertiesRouteDefinitionLocator 使用 Spring Boot 的@ConfigurationProperties 机制加载属性。

上面的配置示例都使用了一个使用位置参数而不是命名参数的快捷符号。 以下两个例子是等效的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
spring:
cloud:
gateway:
routes:
- id: setstatus_route
uri: https://example.org
filters:
- name: SetStatus
args:
status: 401
- id: setstatusshortcut_route
uri: https://example.org
filters:
- SetStatus=401

对于网关的一些用法,属性是足够的,但是一些生产用例将受益于从外部源(例如数据库)加载配置。 未来的里程碑版本将具有基于 Spring Data Repositories 的 RouteDefinitionLocator 实现,例如:Redis,MongoDB 和 Cassandra。

5.1 流式路由配置

为了允许在 Java 中进行简单配置,在 RouteLocatorBuilder bean 中定义了一个流式的 API。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 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")
)
.route(r -> r.order(-1)
.host("**.throttle.org").and().path("/get")
.filters(f -> f.filter(throttle.apply(1,
1,
10,
TimeUnit.SECONDS)))
.uri("http://httpbin.org:80")
)
.build();
}

此样式还允许更多自定义谓词断言。 RouteDefinitionLocator bean 定义的谓词使用逻辑和组合。 通过使用流畅的 Java API,您可以在 Predicate 类上使用 and(),或()和 negate()运算符。

5.2 由定义定位器

可以将网关配置为基于在 DiscoveryClient 兼容服务注册中心注册的服务来创建路由。

要启用此功能,请设置spring.cloud.gateway.discovery.locator.enabled = true并确保DiscoveryClient实现位于类路径上并已启用(例如 Netflix Eureka,Consul 或 Zookeeper)。

默认情况下,Gateway 为通过DiscoveryClient创建的路由定义单个 Predicate 和过滤器。

默认 Predicate 是使用模式/serviceId/**定义的路径 Predicate,其中 serviceId 是DiscoveryClient中服务的 id。

默认过滤器是重写路径过滤器,其中包含正则表达式/serviceId/(?<remaining>.*)和替换/${remaining}。 这只是在向下游发送请求之前从路径中剥离服务 ID。

如果您想自定义DiscoveryClient路由使用的 Predicate,可以通过设置spring.cloud.gateway.discovery.locator.predicates [x]spring.cloud.gateway.discovery.locator.filters[Y]来实现。 执行此操作时,如果要保留该功能,则需要确保包含上面的默认 Predicate 和过滤器。 下面是一个这样的例子。

1
2
3
4
5
6
7
8
9
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}'"

5.3 Reactor Netty 访问日志

要启用 Reactor Netty 访问日志,请设置-Dreactor.netty.http.server.accessLogEnabled = true。 (它必须是 Java System 属性,而不是 Spring Boot 属性)。

可以将日志记录系统配置为具有单独的访问日志文件。 以下是一个示例 logback 配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
<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>

5.4 跨域设置

网关可以配置为控制 CORS 行为。 “全局”CORS 配置是 Spring Framework CorsConfiguration的 URL 模式映射。

1
2
3
4
5
6
7
8
9
spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]':
allowedOrigins: "https://docs.spring.io"
allowedMethods:
- GET

在上面的示例中,对于所有 GET 请求的路径,将允许来自docs.spring.io的请求的 CORS 请求。

5.5 Actuator API

gateway 执行器端点允许监视 Spring Cloud Gateway 应用程序并与之交互。 要进行远程访问,必须在应用程序属性中通过 HTTP 或 JMX 启用和公开端点。

1
2
management.endpoint.gateway.enabled=true # default value
management.endpoints.web.exposure.include=gateway
5.5.1 查看全局过滤器

要检索应用于所有路由的全局过滤器,请向/ actuator / gateway / globalfilters 发出 GET 请求。 结果响应类似于以下内容:

1
2
3
4
5
6
7
8
9
10
{
"org.springframework.cloud.gateway.filter.LoadBalancerClientFilter@77856cc5": 10100,
"org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@4f6fd101": 10000,
"org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@32d22650": -1,
"org.springframework.cloud.gateway.filter.ForwardRoutingFilter@106459d9": 2147483647,
"org.springframework.cloud.gateway.filter.NettyRoutingFilter@1fbd5e0": 2147483647,
"org.springframework.cloud.gateway.filter.ForwardPathFilter@33a71d23": 0,
"org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@135064ea": 2147483637,
"org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@23c05889": 2147483646
}

响应包含有关全局过滤器的详细信息。 对于每个全局过滤器,提供过滤器对象的字符串表示(例如,org.springframework.cloud.gateway.filter.LoadBalancerClientFilter@77856cc5)以及过滤器链中的相应顺序。

5.5.2 路由过滤器

要检索应用于路由的 GatewayFilter 工厂,请向/actuator/gateway/routefilters发出 GET 请求。 结果响应类似于以下内容:

1
2
3
4
5
{
"[AddRequestHeaderGatewayFilterFactory@570ed9c configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null,
"[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]": null,
"[SaveSessionGatewayFilterFactory@4449b273 configClass = Object]": null
}

响应包含应用于任何特定路由的 GatewayFilter 工厂的详细信息。 为每个工厂提供相应对象的字符串表示(例如,[SecureHeadersGatewayFilterFactory @ fceab5d configClass = Object])。 请注意,null 值是由于端点控制器的实现不完整,因为它尝试设置过滤器链中对象的顺序,这不适用于 GatewayFilter 工厂对象。

5.5.3 刷新路由缓存

要清除路由缓存,请对/actuator/gateway/refresh发出 POST 请求。 请求返回 200 且没有响应正文。

5.5.4 检索网关中定义的路由

要检索网关中定义的路由,请对/actuator/gateway/routes发出 GET 请求。 结果响应类似于以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[{
"route_id": "first_route",
"route_object": {
"predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@1e9d7e7d",
"filters": [
"OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.PreserveHostHeaderGatewayFilterFactory$$Lambda$436/674480275@6631ef72, order=0}"
]
},
"order": 0
},
{
"route_id": "second_route",
"route_object": {
"predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@cd8d298",
"filters": []
},
"order": 0
}]

响应包含网关中定义的所有路由的详细信息。 下表描述了响应的每个元素(即路由)的结构。

5.5.5 检索有关特定路线的信息

要检索有关单个路由的信息,请向/actuator/gateway/routes/{id}发出 GET 请求(例如,/actuator/gateway/routes/first_route)。 结果响应类似于以下内容:

1
2
3
4
5
6
7
8
9
10
{
"id": "first_route",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"/first"}
}],
"filters": [],
"uri": "https://www.uri-destination.org",
"order": 0
}]
5.5.6 创建和删除特定路线

要创建路由,请使用指定路由字段的 JSON 主体向/gateway/routes/{id_route_to_create}发出 POST 请求。

要删除路由,请对/gateway/routes/{id_route_to_delete}发出 DELETE 请求。

六 开发文档

6.1 自定义 GatewayFilter

为了编写 GatewayFilter,您需要实现GatewayFilterFactory。 有一个名为AbstractGatewayFilterFactory的抽象类,您可以扩展它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
}

}

6.2 自定义全局过滤器

要编写自定义全局过滤器,您需要实现 GlobalFilter 接口。 这将过滤器应用于所有请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@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();
}

6.3 使用 Spring MVC 或 Webflux 构建简单网关

Spring Cloud Gateway 提供了一个名为ProxyExchange的实用程序对象,您可以在常规 Spring Web 处理程序中将其用作方法参数。 它通过镜像 HTTP Predicate 的方法支持基本的下游 HTTP 交换。 使用 MVC,它还支持通过forward()方法转发到本地处理程序。 要使用ProxyExchange,只需在类路径中包含正确的模块(spring-cloud-gateway-mvcspring-cloud-gateway-webflux)。

MVC 示例(代理向远程服务器下游/test的请求):

1
2
3
4
5
6
7
8
9
10
11
12
13
@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 也是如此:

1
2
3
4
5
6
7
8
9
10
11
12
13
@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 路径。 例如,您可能希望提取路径的尾随元素以将其传递到下游:

1
2
3
4
5
@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 的所有功能都可用于 Gateway 处理程序方法。 例如,您可以注入请求标头和查询参数,并且您可以使用映射注释中的声明来约束传入的请求。 有关这些功能的更多详细信息,请参阅 Spring MVC 中的@RequestMapping文档。

可以使用ProxyExchange上的header()方法将请求头添加到下游响应中。

您还可以通过向get()等方法添加映射器来操作响应标头(以及响应中您喜欢的任何其他内容)。 映射器是一个 Function,它接收传入的ResponseEntity并将其转换为传出的ResponseEntity

网关支持为“敏感”请求头题(默认情况下为“cookie”和“authorization”)提供了一流的支持,这些标题不向下游传递,也为“代理”请求头(x-forwarded- *)提供。