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 | <dependency> |
1.2 配置属性
在属性配置文件里加入以下配置
1 | server: |
spring.cloud.gateway.discovery.locator.enabled
为true
表明 gateway 开启服务注册和发现的功能,spring cloud gateway 自动根据发现的服务为每一个服务创建了一个 router,这个 router 将以服务名开头的请求路径转发到对应的服务。
spring.cloud.gateway.discovery.locator.lowerCaseServiceId
是将请求路径上的服务名配置为小写(因为服务注册的时候,向注册中心注册时将服务名转成大写的了)
1.3 自定义路由
在默认情况下,向网关发送的请求时,url 必须带上服务名service-demo
这个前缀,才能转发到service-demo
上,网关会在转发之前会将service-demo
去掉。
如果有时候因为项目需求需要自定义转发路径,我们设置自己的转发规则:
1 | spring: |
在上面的配置中,网关会将以/demo/**
开头的请求都会转发到 uri 为lb://SERVICE-DEMO
的地址上,其中lb://SERVICE-DEMO
是service-demo
服务的负载均衡地址,并用StripPrefix
的filter
在转发之前将/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 | spring: |
2.2 Before Route Predicate
Before Route Predicate,可配置一个时间,当请求的时间在配置时间之前,才交给 router 去处理
1 | spring: |
2.3 Between Route Predicate
Between Route Predicate,可配置两个时间,当请求的时间在配置时间之间,才交给 router 去处理
1 | spring: |
2.4 Cookie Route Predicate
Cookie Route Predicate Factory 有两个参数,cookie 名称和正则表达式。 此 Predicate 匹配具有给定名称且值与正则表达式匹配的 cookie。
1 | spring: |
此路由匹配请求有一个名为 chocolate 的 cookie,其值与 ch.p 正则表达式匹配。
2.5 Header Route Predicate
Header Route Predicate 工厂采用两个参数,请求头名称和正则表达式。 此 Predicate 与具有给定名称且值与正则表达式匹配的请求头匹配。
1 | spring: |
如果请求具有名为 X-Request-Id 的请求头,则该路由匹配,其值与\d+
正则表达式匹配(具有一个或多个数字的值)
2.6 Host Route Predicate
Host Route Predicate Factory 采用一个参数:多个主机名匹配规则。 该匹配模式是一种.
作为分隔符,采用 Ant 风格匹配。 此 Predicate 匹配与模式匹配的 Host 请求头。
1 | spring: |
也支持 URI 模板变量,例如{sub}.myhost.org
。
如果请求的主机头具有值www.somehost.org
或beta.somehost.org
或www.anotherhost.org
,则将匹配此路由。
此 Predicate 将 URI 模板变量(如上例中定义的 sub)提取为名称和值的映射,可以根据键ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE
从ServerWebExchange.getAttributes()
中获取其中的值,也可以在GatewayFilter Factories
使用这些值。
2.7 Method Route Predicate
Method Route Predicate Factory 采用一个参数:要匹配的 HTTP 方法。
1 | spring: |
如果请求方法是 GET,则此路由将匹配。
2.8 Path Route Predicate
Path Route Predicate Factory 有两个参数:多个的 Spring PathMatcher
匹配规则和可选的matchOptionalTrailingSeparator
标志。
1 | spring: |
则此路由将匹配例如:/foo/1
或/foo/bar
或/bar/baz
形式的路径。
此 Predicate 将 URI 模板变量(如上例中定义的segment
)提取为名称和值的映射,并将其放在ServerWebExchange.getAttributes()
中,根据键ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE
从中获取对应的值,也可以在GatewayFilter Factories
使用这些值。
可以使用实用程序方法来更轻松地访问这些变量,调用方法如下。
1 | Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange); |
2.9 Query Route Predicate
Query Route Predicate Factory 有两个参数:一个必需的参数和一个可选的正则表达式。
1 | spring: |
如果请求包含 baz 查询参数,则此路由将匹配。
1 | spring: |
如果请求包含其值与 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 | spring: |
如果请求的远程地址是例如 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 | spring: |
这将为所有匹配请求的下游请求头添加 X-Request-Foo:Bar 请求头。
3.2 AddRequestParameter
AddRequestParameter GatewayFilter Factory 采用名称和值参数。
1 | spring: |
这会将foo=bar
添加到下游请求的所有匹配请求的查询字符串中。
3.3 AddResponseHeader
AddResponseHeader GatewayFilter Factory 采用名称和值参数。
1 | spring: |
这会将X-Response-Foo:Bar
请求头添加到所有匹配请求的下游响应标头中。
3.4 DedupeResponseHeader
DedupeResponseHeader GatewayFilter Factory 采用名称参数和可选策略参数。 name 可以包含标题名称列表,空格分隔。
1 | spring: |
在网关 CORS 逻辑和下游添加它们的情况下,这将删除Access-Control-Allow-Credentials
和Access-Control-Allow-Origin
响应头的重复值。
DedupeResponseHeader 过滤器还接受可选的策略参数。 接受的值为RETAIN_FIRST
(默认值),RETAIN_LAST
和RETAIN_UNIQUE
。
3.5 Hystrix
Hystrix 是一个实现了断路器模式的 Netflix 库。 Hystrix GatewayFilter 允许您将断路器引入网关路由,保护您的服务免受级联故障的影响,并允许您在下游故障时提供回退响应。
要在项目中启用 Hystrix GatewayFilters,请在 Spring Cloud Netflix 上添加spring-cloud-starter-netflix-hystrix
的依赖。
Hystrix GatewayFilter Factory 需要单个名称参数,该参数是HystrixCommand
的名称。
1 | spring: |
这将使用一个名为 myCommandName 的HystrixCommand
。
Hystrix 过滤器还可以接受可选的fallbackUri
参数,fallbackUri
参数目前仅支持forward:schemed URIs
。 如果调用了回退,则请求将被转发到与 URI 匹配的控制器。
1 | spring: |
当调用 Hystrix 后备时,这将转发到/incaseoffailureuset
这个 URI。 请注意,此示例还通过目标 URI 上可选的 lb 前缀实现负载平衡。
主要方案是将 fallbackUri 用于网关应用程序内的内部控制器或处理程序。 但是,也可以将请求重新路由到外部应用程序中的控制器或处理程序,如下所示:
1 | spring: |
在此示例中,网关应用程序中没有设置回退端点或处理程序,但是在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 | spring: |
在此示例中,在运行 HystrixCommand 时发生执行异常后,会将请求转发到在localhost:9994
上运行的应用程序中的回退端点或处理程序。 导致异常的异常类型消息和-if available- root
的请求头会由 FallbackHeaders 过滤器添加到该请求的请求头中。
通过设置下面列出的参数的值及其默认值,可以在配置中覆盖标头的名称:
1 | - executionExceptionTypeHeaderName ("Execution-Exception-Type") |
3.7 PrefixPath
PrefixPath GatewayFilter Factory 采用单个前缀参数。
1 | spring: |
这将匹配到所有以/mypath
前缀的路径,并将请求/hello
转发到/mypath/hello
。
3.8 PreserveHostHeader
PreserveHostHeader GatewayFilter Factory 没有参数。 此过滤器设置路由过滤器将检查的请求属性,以确定是否应发送原始主机头,而不是 http 客户端确定的主机头。
1 | spring: |
3.9 RequestRateLimiter
RequestRateLimiter GatewayFilter Factory 使用RateLimiter
实现来确定是否允许当前请求继续。 如果不是,则返回 HTTP 429 - Too Many Requests(默认情况下)的状态。
此过滤器采用可选的keyResolver
参数和特定于速率限制器的参数(参见下文)。
keyResolver
是一个实现KeyResolver
接口的 bean。 在配置中使用 SpEL 按名称引用 bean。例如 #{@ myKeyResolver}
是一个引用名为myKeyResolver
的 bean 的 SpEL 表达式。
1 | public interface KeyResolver { |
PrincipalNameKeyResolver
是KeyResolver
的一个默认实现,它从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 | # INVALID SHORTCUT CONFIGURATION |
Redis RateLimiter
这个 redis 扩展在 Stripe 基础上基于令牌桶算法完成的实现,它需要项目引入spring-boot-starter-data-redis-reactive
启动器。
redis-rate-limiter.replenishRate
表示希望允许用户每秒执行多少请求,而不会丢弃任何请求。 这是令牌桶填充的速率。
redis-rate-limiter.burstCapacity
是用户在一秒钟内允许执行的最大请求数。 这是令牌桶可以容纳的令牌数。 将此值设置为零将阻止所有请求。
可以通过在replenishRate
和burstCapacity
中设置相同的值来实现稳定的速率,也可以通过将burstCapacity
设置为高于replenishRate
来允许临时突发。 在这种情况下,需要在突发之间根据replenishRate
允许速率限制器一段时间,因为连续 2 次突发将导致请求被丢弃(HTTP 429 - Too Many Requests)。
配置数据
1 | spring: |
java 代码
1 | @Bean |
这定义了每个用户 10 的请求率限制。 允许突发 20,但下一秒只有 10 个请求可用。 KeyResolver
是一个简单的获取用户请求参数(注意:这不建议用于生产)。
速率限制器也可以使用实现RateLimiter
接口的 bean 来定义, 在配置中使用 SpEL 按名称引用 bean。 #{@ myRateLimiter}
是一个引用名为myRateLimiter
的 bean 的 SpEL 表达式。
1 | spring: |
3.10 RedirectTo
RedirectTo GatewayFilter Factory 采用status
和url
参数。 状态应该是 300 系列重定向 http 代码,例如 301. url 应该是有效的 URL。 这将是 Location 标头的值。
1 | spring: |
这将发送状态 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 | spring: |
这将在向下游发送之前删除X-Request-Foo
请求头。
3.13 RemoveResponseHeader
RemoveResponseHeader GatewayFilter Factory 采用名称参数。 它是要删除的标头的名称。
1 | spring: |
这将在响应返回到网关客户端之前从响应中删除X-Response-Foo
标头。
要删除任何类型的敏感标头,您应该为您可能要执行此操作的任何路由配置此过滤器。 此外,您可以使用spring.cloud.gateway.default-filters
配置此过滤器并将其应用于所有路由 z 中。
3.14 RewritePath
RewritePath GatewayFilter Factory 采用路径正则参数和替换参数。 这使用 Java 正则表达式来灵活地重写请求路径。
1 | spring: |
对于/foo/bar
的请求路径,这将在发出下游请求之前将路径设置为/bar
。 注意由于 YAML 规范,$
替换为$\
。
3.15 RewriteResponseHeader
RewriteResponseHeader GatewayFilter Factory 采用名称,正则表达式和替换参数。 它使用 Java 正则表达式以灵活的方式重写响应头值。
1 | spring: |
对于标题值/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 | spring: |
如果要将 Spring Security 与 Spring Session 集成并且希望确保将安全性详细信息转发到远程进程,则这个配置很关键。
3.17 SecureHeaders
SecureHeaders GatewayFilter Factory 为响应添加了许多标头。
添加以下标头(以及默认值):
1 | X-Xss-Protection:1; mode=block |
要更改默认值,请在spring.cloud.gateway.filter.secure-headers
设置相应的属性:
1 | xss-protection-header |
要禁用默认值,请使用逗号分隔值设置属性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 | spring: |
对于/foo/bar
的请求路径,这将在发出下游请求之前将路径设置为/bar
。
3.19 SetResponseHeader
SetResponseHeader GatewayFilter Factory 获取名称和值参数。
1 | spring: |
此 GatewayFilter 用给定名称替换所有标头,而不是添加。 因此,如果下游服务器包含X-Response-Foo:1234
响应,则将替换为X-Response-Foo:Bar
,这是网关客户端将接收的内容。
3.20 SetStatus
SetStatus GatewayFilter Factory 采用单个状态参数。 它必须是有效的HttpStatus
, 它可以是整数值 404 或 NOT_FOUND 的枚举字符串表示形式。
1 | spring: |
在任何一种情况下,响应的 HTTP 状态都将设置为 401。
3.21 StripPrefix
StripPrefix GatewayFilter Factory 采用一个参数,即部件。 parts 参数指示在向下游发送之前从请求中剥离的路径中的部分数。
1 | spring: |
当通过网关向/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 | spring: |
重试过滤器当前不支持使用正文重试(例如,对于具有正文的 POST 或 PUT 请求)。
当使用带有转发前缀 URL 的重试过滤器时,应仔细编写目标端点,以便在出现错误时不会执行任何可能导致响应发送到客户端并提交的操作。 例如,如果目标端点是带注释的控制器,则目标控制器方法不应返回带有错误状态代码的 ResponseEntity。 相反,它应抛出异常或发出错误信号,例如 通过Mono.error(ex)
返回值,可以将重试过滤器配置为通过重试来处理。
3.23 RequestSize
当请求大小大于允许的限制时,RequestSize GatewayFilter Factory 可以限制请求到达下游服务。 过滤器将RequestSize
作为参数,该参数是以字节为单位定义的请求的允许大小限制。
1 | spring: |
当请求因大小而被拒绝时,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 | @Bean |
3.25 ModifyResponseBody
此过滤器被视为 BETA,API 可能在将来发生变化
此过滤器可用于在将响应主体发送回客户端之前对其进行修改。
1 | @Bean |
3.26 Default Filters
如果您想添加过滤器并将其应用于所有路线,可以使用 spring.cloud.gateway.default-filters。 此属性采用过滤器列表
1 | spring: |
四 全局过滤器
GlobalFilter 接口与 GatewayFilter 具有相同的签名, 这些是有条件地应用于所有路线的特殊过滤器。 (此接口和用法可能会在未来的里程碑中发生变化)。
4.1 过滤器排序
当请求进入(并匹配路由)时,Filtering Web Handler 会将 GlobalFilter 的所有实例和 GatewayFilter 的所有路由特定实例添加到过滤器链。 这个组合的过滤器链由org.springframework.core.Ordered
接口排序,可以通过实现getOrder()
方法或使用@Order
注释来设置。
由于 Spring Cloud Gateway 区分了过滤器逻辑执行的“前”和“后”阶段,第一个前置过滤器和最后一个后置过滤器具有最高优先级。
1 | @Bean |
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 | spring: |
默认情况下,在 LoadBalancer 中找不到服务实例时,将返回 503。 您可以通过设置 spring.cloud.gateway.loadbalancer.use404 = true 来配置网关以返回 404。
从 LoadBalancer 返回的ServiceInstance
的isSecure
值将覆盖在对网关发出的请求中指定的方案。 例如,如果请求通过 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 | spring: |
4.8 Gateway Metrics Filter
要启用 Gateway Metrics,请将spring-boot-starter-actuator
添加为项目依赖项。 然后,默认情况下,只要属性spring.cloud.gateway.metrics.enabled
未设置为false
,网关指标筛选器就会运行。 此过滤器添加名为“gateway.requests”的计时器度量标准,其中包含以下标记:
1 | routeId:路由ID |
然后可以从/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 的配置由RouteDefinitionLocator
s 的集合驱动。
1 | public interface RouteDefinitionLocator { |
默认情况下,PropertiesRouteDefinitionLocator 使用 Spring Boot 的@ConfigurationProperties 机制加载属性。
上面的配置示例都使用了一个使用位置参数而不是命名参数的快捷符号。 以下两个例子是等效的:
1 | spring: |
对于网关的一些用法,属性是足够的,但是一些生产用例将受益于从外部源(例如数据库)加载配置。 未来的里程碑版本将具有基于 Spring Data Repositories 的 RouteDefinitionLocator 实现,例如:Redis,MongoDB 和 Cassandra。
5.1 流式路由配置
为了允许在 Java 中进行简单配置,在 RouteLocatorBuilder bean 中定义了一个流式的 API。
1 | // static imports from GatewayFilters and RoutePredicates |
此样式还允许更多自定义谓词断言。 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 | spring.cloud.gateway.discovery.locator.predicates[0].name: Path |
5.3 Reactor Netty 访问日志
要启用 Reactor Netty 访问日志,请设置-Dreactor.netty.http.server.accessLogEnabled = true
。 (它必须是 Java System 属性,而不是 Spring Boot 属性)。
可以将日志记录系统配置为具有单独的访问日志文件。 以下是一个示例 logback 配置:
1 | <appender name="accessLog" class="ch.qos.logback.core.FileAppender"> |
5.4 跨域设置
网关可以配置为控制 CORS 行为。 “全局”CORS 配置是 Spring Framework CorsConfiguration
的 URL 模式映射。
1 | spring: |
在上面的示例中,对于所有 GET 请求的路径,将允许来自docs.spring.io
的请求的 CORS 请求。
5.5 Actuator API
gateway 执行器端点允许监视 Spring Cloud Gateway 应用程序并与之交互。 要进行远程访问,必须在应用程序属性中通过 HTTP 或 JMX 启用和公开端点。
1 | management.endpoint.gateway.enabled=true # default value |
5.5.1 查看全局过滤器
要检索应用于所有路由的全局过滤器,请向/ actuator / gateway / globalfilters 发出 GET 请求。 结果响应类似于以下内容:
1 | { |
响应包含有关全局过滤器的详细信息。 对于每个全局过滤器,提供过滤器对象的字符串表示(例如,org.springframework.cloud.gateway.filter.LoadBalancerClientFilter@77856cc5
)以及过滤器链中的相应顺序。
5.5.2 路由过滤器
要检索应用于路由的 GatewayFilter 工厂,请向/actuator/gateway/routefilters
发出 GET 请求。 结果响应类似于以下内容:
1 | { |
响应包含应用于任何特定路由的 GatewayFilter 工厂的详细信息。 为每个工厂提供相应对象的字符串表示(例如,[SecureHeadersGatewayFilterFactory @ fceab5d configClass = Object]
)。 请注意,null 值是由于端点控制器的实现不完整,因为它尝试设置过滤器链中对象的顺序,这不适用于 GatewayFilter 工厂对象。
5.5.3 刷新路由缓存
要清除路由缓存,请对/actuator/gateway/refresh
发出 POST 请求。 请求返回 200 且没有响应正文。
5.5.4 检索网关中定义的路由
要检索网关中定义的路由,请对/actuator/gateway/routes
发出 GET 请求。 结果响应类似于以下内容:
1 | [{ |
响应包含网关中定义的所有路由的详细信息。 下表描述了响应的每个元素(即路由)的结构。
5.5.5 检索有关特定路线的信息
要检索有关单个路由的信息,请向/actuator/gateway/routes/{id}
发出 GET 请求(例如,/actuator/gateway/routes/first_route
)。 结果响应类似于以下内容:
1 | { |
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 | public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> { |
1 | public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> { |
6.2 自定义全局过滤器
要编写自定义全局过滤器,您需要实现 GlobalFilter 接口。 这将过滤器应用于所有请求。
1 | @Bean |
6.3 使用 Spring MVC 或 Webflux 构建简单网关
Spring Cloud Gateway 提供了一个名为ProxyExchange
的实用程序对象,您可以在常规 Spring Web 处理程序中将其用作方法参数。 它通过镜像 HTTP Predicate 的方法支持基本的下游 HTTP 交换。 使用 MVC,它还支持通过forward()
方法转发到本地处理程序。 要使用ProxyExchange
,只需在类路径中包含正确的模块(spring-cloud-gateway-mvc
或spring-cloud-gateway-webflux
)。
MVC 示例(代理向远程服务器下游/test
的请求):
1 | @RestController |
Webflux 也是如此:
1 | @RestController |
ProxyExchange
上有一些便捷方法,使处理程序方法能够发现和增强传入请求的 URI 路径。 例如,您可能希望提取路径的尾随元素以将其传递到下游:
1 | @GetMapping("/proxy/path/**") |
Spring MVC 或 Webflux 的所有功能都可用于 Gateway 处理程序方法。 例如,您可以注入请求标头和查询参数,并且您可以使用映射注释中的声明来约束传入的请求。 有关这些功能的更多详细信息,请参阅 Spring MVC 中的@RequestMapping
文档。
可以使用ProxyExchange
上的header()
方法将请求头添加到下游响应中。
您还可以通过向get()
等方法添加映射器来操作响应标头(以及响应中您喜欢的任何其他内容)。 映射器是一个 Function,它接收传入的ResponseEntity
并将其转换为传出的ResponseEntity
。
网关支持为“敏感”请求头题(默认情况下为“cookie”和“authorization”)提供了一流的支持,这些标题不向下游传递,也为“代理”请求头(x-forwarded- *
)提供。