Spring Cloud Gateway 官方文档试译
本文尝试着翻译一下Spring Cloud Gateway的官方文档,对应版本2.2.4.BUILD-SNAPSHOT。旨在加深本人对Spring Cloud Gateway的理解和使用。
如果不幸被其他人看到了,那烦请高抬贵嘴,第一次翻译,难免有不足之处。
2.2.4.BUILD-SNAPSHOT
此项目孵化了一个基于Spring生态系统:包括,Spring 5,Spring Boot 2和Project Reactor的API网关。Spring Cloud Gateway旨在提供一个简单,有效的路由API的方式,并提供了安全,监控/指标,以及弹性相关的横切关注。
如何引入Spring Cloud Gateway
如果要在自己的项目中引入Spring Cloud Gateway,你只需要在pom(以maven为例)中引入groupId为org/springframeword.cloud
,artifact id为spring-cloud-starter-gateway
的spring cloud starter即可。可以访问这里,获取更新详细的信息。
注意:Spring Cloud Gateway 是基于Spring Boot 2.X,Spring WebFlux和Project Reactor的。因此,大部分常见的同步库(比如,Spring Data和Spring Security)和模式可能不适用于Spring Cloud Gateway。如果你不熟悉这些项目,我们建议你在使用Spring Cloud Gateway之前,先阅读下他们的官方文件,预先对一些概念有些了解。
Spring Cloud Gateway 依赖Srping Boot 和 Spring WebFlux提供的Netty 运行环境。它不适用于传统的Servlet容器(比如低版本的tomcat等),也不适合打成WAR包。
概念释义
- 路由:是网关的基本构件。它由一个ID,一个目标URI,一些列的断言和一系列的过滤器组成。如果断言威震,则路由匹配,目标URI会被访问。
- 断言:这是一个Java 8 中的断言,输入类型是Spring框架的ServerWebExchange。它可以匹配来自HTTP请求的任意内容,比如,请求头或者参数。
- 过滤器:它们是Spring框架的GatewayFilter,可以通过一些特定的工厂创建。我们可以通过它们来修改请求或者响应。
Spring Cloud Gateway 如何工作
下图从总体上概述了Spring Cloud Gateway的工作方式:
客户端向Spring Cloud Gateway发出请求。如果Gateway Hanlder mapping认为请求与路由匹配,那么会将请求转发给Gateway Web Handler。Gateway Web Handler会运行一系列针对这个请求的过滤器。过滤器由虚线分隔的原因是,过滤器可以在发情代理请求之前和之后运行。在发出代理请求之前,执行所有前置(“pre”)过滤器。在发出代理请求之火,执行所有后置(“post”)过滤器。
配置路由断言工厂和网关路由器断言工厂
有两种方法可以配置断言和过滤器:快捷配置和完全展开配置。下面的大多数示例都是用快捷配置。
名称和参数名称会在每个部分的第一句或者第二句作为代码列出。参数通常按照快捷配置所需的顺序列出。
快捷配置
快捷配置方式由路由器名称作为起始,后跟等号(=),再跟着由逗号(,)分隔的参数。
application.yml
1 | spring: |
上面的例子定义了一个Cookie路由断言工厂。它接收两个参数,cookie名称,mycookie
和需要匹配的cookie值mycookievalue
。
全扩展配置
全扩展配置看起来更像标准的yaml 键值对配置。通常来说,会有一个name
的键,对应一个args
的值。args
值一般是一系列的键值对,用来配置断言或者过滤器。
application.yml
1 | spring: |
上面是上一个Cookie断言的全扩展配置版本。
路由断言工厂
Spring Cloud Gateway将路由作为Spring WebFlux HandlerMapping基础架构的一部分。 Spring Cloud Gateway包含了许多内置的路由断言工厂。所有这些断言都与HTTP请求的不同属性匹配。你可以任意组合多个路由断言工厂使用。
After 路由断言工厂
After
路由断言工厂接收一个时间参数,datetime
(java ZonedDateTime
对象)。这个路由匹配指定时间之后的请求。
示例1:application.yml
1 | spring: |
这个路由匹配任何在时间2017-01-20T17:42:47.789-07:00[America/Denver
的请求。
Before 路由断言工厂
Before路由断言工厂,接收一个时间参数,datetime
(java ZonedDateTime
对象)。这个路由匹配任意在这个时间点之前的请求。
示例2:application.yml
1 | spring: |
这个路由匹配所有在这个时间点(2017-01-20T17:42:47.789-07:00[America/Denver]
)之前的请求。
Between 路由断言工厂
Between
路由断言工厂接收两个参数,datetime1
(java ZonedDateTime
对象)和datetime2
(java ZonedDateTime
对象)。这个断言匹配所有在datetime1
之后,datetime2
之前的请求。时间datetime2
一定要在datetime1
之前。
示例3:application.yml
1 | spring: |
上面的路由匹配任何间于时间2017-01-20T17:42:47.789-07:00[America/Denver]
和时间2017-01-21T17:42:47.789-07:00[America/Denver]
之间的请求。
Cookie 路由断言工厂
Cookie路演断言工厂接收两个参数,cookie的name
和regexp
(Java的正则表达是)。这个路由断言工厂匹配那些Cookie名称匹配,并且Cookie值匹配正则表达式(regexp)的请求。
示例4:application.yml
1 | spring: |
这个路由匹配那些具有名为chocolate,值匹配ch.p
的cookie的请求。
Header 路由断言工厂
Header路由断言工厂接收两个参数,请求头名称name
和请求头的值regexp
(Java正则表达式)。这个路由匹配所有请求头名称为name,请求头值匹配regexp的请求。
示例5:application.yml
1 | spring: |
这个路由匹配所有请求中包含请求头X-Request-Id
,请求头值为1个或多个数字(\d+
)的请求。
Host 路由断言工厂
Host路由断言工厂接收一个参数:主机名字列表。主机名字以逗号分割,名字内可以用.
作为分割符。
示例6:application.yml
1 | spring: |
URI模板参数({sub}.myhost.org)也是支持。
此路由匹配所有请求Host具有值www.somehost.org
或者beta.somehost.org
抑或是www.anotherhost.org
的请求。
这个路由断言从uri模板中抽取参数作为键值对,存入ServerWebExchange.getAttributes()
,存入键名为ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE
。
Method 路由断言工厂
Method路由断言工厂接收一个methods
参数。该参数可以是一个或者多个HTTP方法。
示例6:application.yml
1 | spring: |
上述的路由匹配所有请求方法为GET
或者POST
的请求。
Path 路由断言工厂
Path路由断言工厂接收两个参数:一个路径列表和一个可选的标记参数matchOptionalTrailingSeparator
.
示例8:application.yml
1 | spring: |
上述路由匹配下面的这些路径/red/1
或者/red/blue
抑或是/blue/green
。
这个路由也会从URI模板中提取参数,作为键值对,存入ServerWebExchange.getAttributes()
的名为ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE
的属性值中。
下面的代码演示了如何获取segement的值:
1 | Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange); |
Query 路由断言工厂
Query路由断言工厂接收两个参数:必选的param
和可选的regexp
(Java正则表达式)。
示例9:application.yml
1 | spring: |
上述的路由匹配,请求查询参数中具有green
这个参数的请求。
1 | spring: |
上述的路由匹配请求中具有参数名为red
和参数值符合gree
的请求。例如,请求https://example.org/hello?red=greet。就会被匹配上。
RemoteAddr Route Predicate Factory
RemoteAddr路由断言工厂接收一个sources
列表,作为参数。参数以CIDR形式表示。
示例10:application.yml
1 | spring: |
上述路由匹配远程地址为192.168.1.1/24
范围内的请求,比如,192.168.1.10
。
Weight Route Predicate Factory
Weight路由断言工厂接收两个参数:group
和weight
(int型)。权重是根据每个组(group)计算的。
示例11:application.yml
1 | spring: |
上述路由会把80%左右的请求导向weighthigh.org,剩下的20%左右导向weightlow.org。
Modifying the Way Remote Addresses Are Resplved
默认情况下,RemoteAddr路由断言工厂使用请求中的远程地址。如果Spring Cloud Gateway身处在一个代理层之后,路由就无法拿到真实的客户端地址。
可以通过设置自定义的RemoteAddressResolver来自定义解析远程地址的方式。Spring Cloud Gateway随附了一个基于X-Forwarded-For请求头的XForwardedRemoteAddressResolver的非默认远程地址解析器。
XForwardedRemoteAddressResolver有两个静态的构造方法。它们使用了不同的实现方式:
XForwardedRemoteAddressResolver::trustAll
:返回一个RemoteAddressResolver。它获取从X-Forwarded-For请求头中第一个发现的IP地址。这种方法是存在弱点的。一个恶意的客户端可以给X-Forwarded-For设置一个任意初始值,该Resolver就会接收该初始值。XForwardedRemoteAddressResolver::maxTrustedIndex
:采用与Spring Cloud Gateway前面运行的受信任基础架构数量相关的索引。例如,如果只能通过HAProxy访问Spring Cloud Gateway,则应使用值1。如果在访问Spring Cloud Gateway之前需要两跳可信基础架构,则应使用值2。
考虑如下请求头值:
1 | X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3 |
以下maxTrustedIndex值产生以下远程地址:
maxTrustedIndex |
result |
---|---|
[Integer.MIN_VALUE ,0] |
(invalid, IllegalArgumentException during initialization) |
1 | 0.0.0.3 |
2 | 0.0.0.2 |
3 | 0.0.0.1 |
[4, Integer.MAX_VALUE ] |
0.0.0.1 |
下面的例子展示用Java代码如何实现相同的配置:
1 | RemoteAddressResolver resolver = XForwardedRemoteAddressResolver |
网关过滤器工厂
路由过滤器允许我们对传入的请求或者传出的相应进行修改。路由过滤器适用于特定的路由。Spring Cloud Gateway内置了许多GatewayFilter工厂。
AddRequestHeader
此路由器工厂接收一个name
和value
作为参数。
示例13:application.yml
1 | spring: |
这个过滤器将会在所有符合条件的请求上加上X-Request-red=blue这个请求头。
AddRequestHeader过滤器也可以从用来匹配的URI中获取变量。变量可以在过滤器中使用,并在运行期间被扩展。如下:
示例14:application.yml
1 | spring: |
AddRequestParameter
这个过滤器接收一个name
和一个value
作为参数。
示例15:application.yml
1 | spring: |
上述配置将会在所有符合条件的请求中,加上red=blue的查询参数。
AddrequestParameter过滤器也可以从匹配的路径或者主机中获取参数。参数可以用来配置过滤器,并在运行期间扩展。
示例16:application.yml
1 | spring: |
AddResponseHeader
此过滤器接收一个name
和value
作为参数,它会在匹配的相应上加上配置的响应头:
示例17:application.yml
1 | spring: |
AddResponseHeader过滤器也可以从匹配的路径或者主机中获取参数。参数可以用来配置过滤器,并在运行期间扩展。
示例18:application.yml
1 | spring: |
DedupeResponseHeader
这个过滤器接收一个name
参数和一个可选的strategy
参数。name
参数由一系列的响应头名称组成,以空格分隔。
示例19:application.yml
1 | spring: |
符合这个条件的响应头将会删除重复的Access-Control-Allow-Credentials
和Access-Control-Allow-Origin
。
strategy
的取值RETAIN_FIRST(default)
,RETAIN_LAST
,RETAIN_UNIQUE
。
Hystrix
注意:Netflix已经将Hystrix置于维护模式了,未来的版本中会被移除。建议使用Spring Cloud CircuitBreaker Gateway Filter。
Hystrix 是 Netflix 的库,实现了断路器模式。Hystrix GatewayFilter允许您将断路器引入网关路由,保护您的服务免受级联故障的影响,并允许在发生下游故障时提供回退响应。
在项目中引用Hsytrix过滤器,在依赖文件中添加spring-cloud-starter-netflix-hystrix
依赖即可。
Hystrix过滤器工厂接收一个name
参数。这个参数代表了HystrixCommand的名字。
示例20:application.yml
1 | spring: |
这些逻辑全部被封装在一个名为myCommandName的HystrixCommand中。
Hystrix过滤器还可以接收一个可选的回退uri参数-fallbackUri。但目前仅支持forward:
。如果回退被处罚了,那么请求将被转发到匹配的URI控制器。
示例21:application.yml
1 | spring: |
当回退被调用时,请求将会被转发到/incaseofffailureuse。注意:这个示例还演示了Sping Cloud Netflix Ribbon 负载均衡的功能(uri中的lb前缀)。
此过滤器主要应用场景是使用回退uri(fallbackUri)路由到内部的控制器或者处理程序。但是,还可以将请求重新路由到外部程序的控制器或者处理程序。如下所示:
示例22:application.yml
1 | spring: |
上面这个例子中,没有配置回退(fallback)的处理器。但是,它配置了一个外部应用的处理器,注册在localhost:9994
下。
伴着请求被转发到fallback
,Hystrix也提供了造成这次回退的原因(Throwable
)。它被存储在ServerWebExchange
的ServerWebExchangeUtils.HYSTRIX_EXECUTION_EXCEPTION_ATTR
属性中。
对于外部控制器/处理程序场景,可以添加包含异常详细信息的请求头。可以在这里找到有关这样做的更多信息。
可以使用应用程序属性将 Hystrix 设置(如超时)配置为全局默认值,也可以在路由上配置,如 Hystrix wiki 上所述。
若要为前面显示的示例路由设置五秒超时,可以使用以下配置:
示例23:application.yml
1 | hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds: 5000 |
Spring Cloud CircuitBreaker
此过滤器使用Spring Cloud CircuitBreaker API将网管路由封装在断路器中。Srping Cloud CircuirBreaker可与Hystrix和Resilience4j一起使用。但由于Netflix已经将Hystrix置于维护模式,因此,建议使用Resilience4j。
将下面两个依赖中的任意一个添加进来,就可以开启Spring Cloud CircuitBreaker 过滤器了:spring-cloud-starter-circuitbreaker-reactor-resilience4j
和spring-cloud-starter-netflix-hystrix
。
示例24:application.yml
1 | spring: |
参加使用的对应组件的文档,如果要配置断路器的话:
Spring Cloud CircuitBreaker过滤器也可以接收一个可选的参数fallbackUri
。当前,只支持forward:
。如果回退了,那么请求就会被发到对应API的控制器去。
示例25:application.yml
1 | spring: |
下面的Java代码完成了相同的事情:
1 |
|
当断路器回退被调用时,上述示例的请求将会被转发到/inCaseofFailureUseThisURI
。需要注意的是,这个示例还演示了(可选)Spring Cloud Netflix Ribbon负载均衡的功能(由目标URI上的lb前缀声明)。
主要的应用场景是在网关应用程序内定义内部控制器或者处理程序。但是还可以将fallbackUri
请求重新路由到外部应用程序的控制器或者处理程序中。如下所示:
示例27:application.yml
1 | spring: |
在上述示例中,网关应用程序中没有设置回退重点或者处理程序。但是在另外一个应用中注册了一个,注册在地址http://localhost:9994下。
如果请求被转发到了回退上,Spring Cloud CircuitBreaker还提供了引起回退的原因一并转发。它保存在ServerWebExchange.ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR属性中。
对于外部控制器或处理程序场景,可以将异常的详细信息添加至请求头。可以参考FallbackHeaders GatewayFilter Factory获取更多信息。
FallbackHeaders
FallbackHeaders过滤器允许在将请求转发值外部回退处理器或者应用程序的时候,将引起回退的异常信息添加至请求头。
示例28:application.yml
1 | spring: |
在上述示例中,当断路器运行时发生异常之后,请求将会被转发到http://localhost:9994上配置的回退控制器或者处理程序。回退的异常类型,消息和引起回退的异常根原因(如果有的话)将会被添加到请求头中。
可以通过设置一下参数的值,来覆盖配置中的默认请求头名称(括号中的是默认值):
- executionExceptionTypeHeaderName (”Execution-Exception-Type”)
- executionExceptionMessageHeaderName (“Execution-Exception-Message”)
- rootCauseExceptionTypeHeaderName (“Root-Cause-Exception-Type”)
- rootCauseExceptionMessageHeaderName (“Root-Cause-Exception-Message”)
MapRequestHeader
此过滤器接收fromHeader
和toHeader
作为参数。它创建一个新的名为toHeader
的请求头并填入fromHeader
请求头对应的值。fromHeader
不存在对此请求头没有影响。如果toHeader
请求头已经存在了,那么它的值将会被增强。下面的示例演示了如何配置MapRequestHeader:
示例29:application.yml
1 | spring: |
上面的配置将会在转发下下游的请求头中加上X-Request-Red
这个请求头,值则从请求头Blue
中获取。
PrefixPath
PrefixPath请求头接收一个prefix
参数。
示例30:application.yml
1 | spring: |
这将在所有匹配的请求路径上添加/mypath
前缀。因此,对/hello
的请求将被发送到/mypath/hello
路径上。
PreserveHostHeader
这个过滤器不接收任何参数。这个过滤器决定请求在转发的时候是否带上原始的主机请求头,而不是由HTTP 客户端确定的请求头。
示例31:application.yml
1 | spring: |
RequestRateLimiter
此过滤器使用RateLimiter来决定是否允许当前请求继续执行。如果不允许,则返回HTTP 429-太多请求。
此过滤器接收一个可选的KeyResolver参数和一些针对于Rate limiter的特定参数。
KeyResolver是一个实现了KeyResolver接口的Bean。在配置中,按照SpEL使用名称引用这个Bean。引用一个名为myKeyResolver
的表达式为#{@myKeyResolver}
。下面就是KeyResolver
接口:
1 | public interface KeyResolver { |
KeySolver 接口允许可插拔策略派生用于限制请求的密钥。在将来的里程碑版本中,将有一些密钥解析器实现。
KeySolveer 的默认实现是PrincipalNameKeyResolver
,它从ServerWebExchange
中获取Principal,并调用Principal.getName()。
默认情况下,如果密钥解析器找不到密钥,请求将被拒绝。可以通过设置 spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key (true或false)和 spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code属性来调整此行为。
Redis RateLimiter
基于Redis的实现是在Stripe的基础上完成的。它要求引入spring-boot-starter-data-redis-reactive
启动器。
使用的算法是令牌桶。
redis-rate-limiter-replenishRate
属性是每秒允许多少个用户请求,不丢弃任何请求。这也是令牌桶填充的速率。
redis-rate-limiter.burstCapacity
是允许用户在一秒中之内可以执行的最大请求数。这也是令牌桶能容纳的最大令牌数。将这个属性设置为0,会阻止所有请求。
redis-rate-limiter.requestedTokens
属性是每个请求所需要的令牌数。即,每次请求会从令牌桶中取的令牌数。默认值为1。
将replenishRate
和burstCapacity
设置为相同的值可以使请求保持在一个稳定的值。将burstCapacty
设置为高于replenishRate
的值,可以允许临时突发的请求。在这种情况下爱,需要允许rate limiter在突发之间的一段时间(根据配置的replenishRate
),因为连续两次突发将导致请求被丢弃(返回HTTP 429,太多请求)。以下的配置配置了一个redis-rate-limiter
:
示例34:application.yml
1 | spring: |
下面的代码,配置了一个KeyResolver。
示例35:Config.java
1 |
|
这个配置定一个每个用户每秒10个请求的限制,突发情况下,允许20个请求每秒。但是在第二秒中,只有10个请求可用,KeyResolver是获取用户请求参数的简单程序(请注意,不建议用于生产环境)。
还可以将rate limiter定义为实现RateLimiter
接口的Bean。在配置中可以使用SpEL按名称引用Bean。myRareLimiter这个Bean在SpEL中就名为#{@myRateLimiter}
。一下idngyige使用上一个样例中的KeyResolver的RateLimiter:
示例36:application.yml
1 | spring: |
RedirectTo
此过滤器接收两个参数status
和url
。status
参数应该为3XX系列的重定向HTTP相应码,如301,302.url
参数应该是有效的URL。它是Location
头的值。对于相对重定向,应该使用no://op
作为路由定义的uri。
示例37:application.yml
1 | spring: |
上述配置将会对状态码为302,Location头的值为https://acme.org的请求重定向。
RemoveRequestHeader
这个过滤器接收一个name
参数。它是待删除的请求头名称。
示例38:application.yml
1 | spring: |
它会在将请求转发到下游之前,将请求头X-Request-Foo
删除
RemoveResponseHeader
这个过滤器接收一个name
参数。它是待删除的响应头名称。
示例39:application.yml
1 | spring: |
它会在请求返回网关应用之前,将响应中的X-Response-Foo
删除。
若要删除任何类型的敏感响应头,可为可能要这样做的任何路由配置此过滤器。此外,还可以通过 spring.cloud.gateway.default配置将此过滤器配置为默认路由,它应用于所有路由。
RemoveRequestParameter
这个过滤器接收一个name
参数。它是待删除的查询参数的名称。
示例40:application.yml
1 | spring: |
上述配置将从请求的查询参数中,删除red这个参数。
RewritePath
这个过滤器接收一个路径的正则表达式参数regexp
和一个replacement
代替着参数。它使用Java中的正则表达式来灵活地重写请求路径。
示例41:application.yml
1 | spring: |
对请求路径/red/blue
来说,在它被转发到下游之前,它将会被改写为/blue
。注意,因为yaml语言规范,$
应该被替换为$\
。
RewriteLocationResponseHeader
该过滤器修改响应头中的Location
字段的值。一般是为了屏蔽后端的一些细节。它接收stripVersionMode
,locationHeaderName
,hostValue
和protocolsRegex
作为参数。
示例42:application.yml
1 | spring: |
举个例子,对请求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
:不管请求什么样,总是剥离版本信息
hostValue
参数如果提供了的话,将会被用来替换Location
中的host:port
部分。如果没有提供,字段Host
中的值将会被使用。
protocolsRegex
参数一定是一个合法的正则表达式。它用来匹配参数中的协议。如果没有协议能匹配上,这个过滤器就不会产生行为。默认值是:http|https|ftp|ftps
。
RewriteResponseHeader
这个过滤器接收name
,regexp
和replacement
作为参数。它使用Java的正则表达式来灵活的重写响应头的值。
示例43:application.yml
1 | spring: |
对于一个请求头为/42?user=ford&password=omg!what&flag=true
的请求,在它被转发到下游之前,该请求头将会被重写为/42?user=ford&password=***&flag=true
。注意,因为yaml语言规范,$
应该被替换为$\
。
SaveSession
这个过滤器在将请求转发到下游前,会强制执行WebSession::save操作。当Spring Session和数据懒存储结合在一起使用时,尤其有效。需要在进行转发调用之前确保会话状态已经保存。
示例44:application.yml
1 | spring: |
如果将 Spring Security 与 Spring 会话集成,并且希望确保安全详细信息已转发到远程进程,则这一点至关重要。
SecureHeaders
按照这篇博客的建议这个过滤器将会添加一系列的请求头至相应中。
下列请求头将会被添加(括号中的为默认值):
- 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
下即可。
1 | spring.cloud.gateway.filter.secure-headers.disable=x-frame-options,strict-transport-security |
SetPath
这个过滤器接收一个路径模板参数template
。它提供了一种简单的通过允许路径模板化来操作请求路径的简单方法。它使用了Spring框架的URI模板。允许匹配多个段。
示例45:application.yml
1 | spring: |
对于请求/red/blue
,在被转发到下游服务之前,它的路径将会被设置为/blue
。
SetRequestHeader
这个过滤器接收一个name
和一个value
作为参数。
示例46:application.yml
1 | spring: |
这个过滤器将会使用配置的值,替换所有的重名请求头。
SetRequestHeader 能感知用于匹配路径或主机的 URI 变量。URI 变量可用于该值,并在运行时扩展。下面的示例配置使用变量的 SetRequestHeader 网关筛选器:
示例47:application.yml
1 | spring: |
SetResponseHeader
这个过滤器接收一个name
和一个value
作为参数。
示例48:application.yml
1 | spring: |
这个过滤器将会使用配置的值,替换所有的重名请求头。
SetResponseHeader 能感知用于匹配路径或主机的 URI 变量。URI 变量可用于该值,并在运行时扩展。下面的示例配置使用变量的 SetResponseHeader 网关筛选器:
示例49:application.yml
1 | spring: |
SetStatus
这个过滤器接收一个参数status
。它必须是一个合法的Spring Http状态码。它可以是整型的404也可以是字符串型的“NOT_FOUND”。
示例50:application.yml
1 | spring: |
在这两种情况下,响应的 HTTP 状态都设置为 401。
可以配置此过滤器,从响应头中的代理请求返回原始 HTTP 状态代码。如果配置了以下属性,则响应头将添加到响应中:
示例51:application.yml
1 | spring: |
StripPrefix
这个过滤器接收一个参数,parts
。参数parts
表示要从请求路径中剥离的数目。
示例52:application.yml
1 | spring: |
当一个请求通过网关访问/name/blue/red
时,它将被剥离成/red
Retry
这个过滤器支持下面的这些参数:
retries
:重试的次数status
:需要被重试的HTTP 状态码。用org.springframeword.http.HttpStatus表示methods
:需要被重试的方法。用org.springframeword.http.HttpMethdo表示。series
:需要被重试的一系列HTTP状态码。用org.springframeword.http.HttpStatus.Series表示exceptions
:需要被重试的异常backoff
:重试退火的时间。退火的间隔计算公式为firstBackoff * (factor ^ n)
。其中n
是第n
次重试。如果配置了maxBackoff
,重试最大间隔时间就不能超过maxBackoff
。如果basedOnPreviousValue
被设置为true,那么回退的计算公式就变为prevBackoff * factor
。
它们的默认值分别是:
retries
:3次methods
:GET方法series
:5XX系列的错误码exceptions
:IOException和TimeoutExceptionbackoff
:disabled
示例53:application.yml
1 | spring: |
RequestSize
当请求大小大于允许的限制时,此过滤器可以限制请求到达下游服务。过滤器接收maxSize
参数。maxSize
是”DataSize 类型”,因此值可以定义为数字,后跟可选的 DataUnit 后缀,如”KB”或”MB”。字节的默认值为”B”。它是以字节为单位定义的请求的允许大小限制。以下列表配置了请求大小网关筛选器:
示例54:application.yml
1 | spring: |
将响应状态设置为 413 ,当请求因大小而被拒绝时,则出现额外的请求头错误消息。下面的示例显示这样的错误消息:
1 | errorMessage` : `Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB |
SetRequestHost
在某些情况下,需要重写主机的请求头。这个过滤器可以用指定的值替换现有的Host请求头。这个过滤器接收一个host
参数。
示例55:application.yml
1 | spring: |
此过滤器将会用example.org
替换host请求中的值。
ModifyRequestBody
这个过滤器允许在请求转发至下游服务之前,修改它的请求体。
注意:这个过滤器只能在Java代码中配置。
1 |
|
ModifyResponseBody
这个过滤器允许在响应回到网关应用之前,修改它的响应体。
注意:这个过滤器只能在Java代码中配置。
1 |
|
Default Filters
可以通过配置spring.cloud.gateway.default-filters
,将一系列的过滤器配置为默认过滤器,以便将它们应用到所有的路由中。
示例54:application.yml
1 | spring: |
全局过滤器
全局过滤器和Gateway过滤器一样具有同样的接口。它们是有条件的应用于所有路由的过滤器。
结合全局过滤器和GatewayFilter Ordering
当请求与路由匹配的时候,filtering Web Handler将会把所有的全局过滤器和所有特定于路由的网关过滤器添加到过滤器链中。它们之间通过org.springframework.core.Order
接口来实现排序。可以通过实现Order
接口的getOrder
方法,来自定义过滤器的优先级。
由于Spring Cloud 网管区分“前置”和“后置”过滤器,因此,优先级最高的“前置”过滤器是第一个执行,在“后置”过滤器中是最后一个执行。
下面的例子,配置了一个过滤器链:
示例57:ExampleConfiguration.java
1 |
|
Forward Routing
ForwardRoutingFilter从exchange的属性ServerWebExchangeUtils.GATEWAY_REQUEST_URI_ATTR
中提取参数。如果这个URI符合forward
模式(forward://myservice),它就使用Spring框架的DispatcherHandler
来处理请求。请求URL的路径部分将会被forward
中的路径部分覆盖。原始的请求头将会被追加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR
属性中。
LoadBalancerClient
这个过滤器从ServerWebExchangeUtils.GATEWAY_REQUEST_URI_ATTR
属性中提取参数。如果URL符合lb
模式(lb://myservice),那么它将会使用Spring Cloud 的LoadBalcnerClient将服务名称(myService)解析为实际的主机和端口,并替换同一属性中的URI。未修改的原始URL将附加到ServerWebExchangeUtils.GATEWAY_ORIGIN_REQUEST_URL_ATTR
属性中。这个过滤器确认属性ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR
的值是否为lb,是的话,则使用相同的规则。
示例58:application.yml
1 | spring: |
默认情况下,如果LoadBalancer无法找到服务的示例,会返回一个503.可以通过配置
spring.cloud.gateway.loadbalancer.use404=true
将网关的返回修改为404.
从服务实例返回的isSecure属性将覆盖向网管发出的请求中指定的值。比如,如果请求通过HTTPS进入网关,但是服务实例认为它不安全,那么就通过HTTP协议转发请求到下游,反之亦然。但是,GATEWAY_SCHEME_PREFIX_ATTR属性为网关配置中的路由指定了一个策略,即删除前缀,并且路由 URL 中生成的方案将覆盖 ServiceInstance 配置。
LoadBalancerClient过滤器使用了一个阻塞式的Ribbon LoadBalancerClient。建议使用ReactiveLoadBalancerClient过滤器。可以通过设置
spring.cloud.loadbalancer.ribbon
的值为false,切换到ReactiveLoadBalancerClient过滤器。
ReactiveLoadBalancerClient
这个过滤器从ServerWebExchangeUtils.GATEWAY_REQUEST_URI_ATTR
属性中提取参数。如果URL符合lb
模式(lb://myservice),那么它将会使用Spring Cloud 的ReactorLoadBalcnerClient将服务名称(myService)解析为实际的主机和端口,并替换同一属性中的URI。未修改的原始URL将附加到ServerWebExchangeUtils.GATEWAY_ORIGIN_REQUEST_URL_ATTR
属性中。这个过滤器确认属性ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR
的值是否为lb,是的话,则使用相同的规则。
示例59:application.yml
1 | spring: |
默认情况下,如果LoadBalancer无法找到服务的示例,会返回一个503.可以通过配置
spring.cloud.gateway.loadbalancer.use404=true
将网关的返回修改为404.
从服务实例返回的isSecure属性将覆盖向网管发出的请求中指定的值。比如,如果请求通过HTTPS进入网关,但是服务实例认为它不安全,那么就通过HTTP协议转发请求到下游,反之亦然。但是,GATEWAY_SCHEME_PREFIX_ATTR属性为网关配置中的路由指定了一个策略,即删除前缀,并且路由 URL 中生成的方案将覆盖 ServiceInstance 配置。
Netty Routing
如果ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
属性是以http
或者https
开头,它将会运行当前过滤器。它使用Netty HttpClient向下游发送代理请求。响应被放在ServerWebExchangeUtils.CLIENT_RESPINSE_ATTR
属性中供后续的过滤器使用。(有个名为WebClientHttpRoutingFilter
的过滤器实现相同的功能,但是不需要Netty)。
Netty Write Response
如果属性ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR
存在一个Netty HttpClientResponse
,那么当前过滤器将会执行。它在所有其他过滤器完成并将代理响应写入网关客户端响应后运行。(还有一个实验性的 WebClientWrite 响应过滤器执行相同的功能,但不需要 Netty。
RouteToRequestUrl
如果ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR
存在一个路由对象,当前请求将运行。它基于请求的URI创建一个新的URI,但使用路由对象的URI属性进行更新。新的URI被放置在ServerWebExchangeeUtils.GATEWAY_REQUEST_URL_ATTR
属性中。
如果URI具有前缀,例如lb:ws://serviceid
,前缀lb将从url中被剥离,并放置在ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR
属性中。供后续的过滤器使用。
Websocket Routing
如果属性ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
中的URI具有ws
或者wss
前缀,当前过滤器将会运行。它使用Spring WebSocket来将websocket请求转发到下游服务。
可以配置URI为lb:ws://serviceid
来达到负载均衡的目的。
示例60:application.yml
1 | spring: |
Gateway Metrics
在项目中添加spring-boot-starter-actuator
依赖可以开启gateway metrixs。接着,只要spring.cloud.gateway.metrics.enabled
属性没有被设置为false,这个过滤器就会执行。这个过滤器会添加一个具有以下标签的计时器指标:
- routeId:路由id
- routerUri:被路由的API
- outcome:结果,通过HttpStatus.Series分类
- status:返回客户端的HTTP状态
- httpStatusCode:返回客户端的HTTP状态码
- httpMethod:请求的HTTP方法
这些指标可以通过/actuator/metrics/gateway.requests
获得。并且可以轻易的和普罗米修斯结合来创建一个Gragana dashboard。
标记一个Exchange为已路由
网关路由了ServerWebExchange之后,它会将gatewayAlreadyRouted
作为属性添加到该exchange中。一旦一个请求被标记为已经路由,其他的路由过滤器将不会再路由这个请求,实际上是跳过该过滤器。可以使用一些简便的方法将exchange标记为已路由或者检查exchange是否已被路由。
ServerWebExchangeUtils.isAlreadyRouted
接收一个ServerWebExchange
对象并检查其是否已经被路由ServerWebExchangeUtils.setAlreadyRouted
接收一个ServerWebExchange
对象并将其标记为”已路由“。
HttpHeaders过滤器
HttpHeaders过滤器应用于向下游发送请求之前。
Forwarded Headers
此过滤器创建一个Forwarded
请求头来发送到下游服务。它将当前请求的Host头,scheme和端口添加到任何现有的Forwarded
头中。
RemoveHopByHopHeaders
该过滤器可以同转发的请求中删除指定的请求头。默认被删除的请求头列表来自IETF。
默认删除的请求头为:
- Connection
- Keep-Alive
- Proxy-Authenticate
- Proxy-Authorization
- TE
- Trailer
- Transfer=Encoding
- Upgrade
可以通过配置属性spring.cloud.gateway.filter.remove-non-proxy-headers.headers
来改变待删除的请求头列表。
XForwarded
XForwarded过滤器在把请求发送到下游服务之前,会创建各种X-Forwarded-×请求头。它使用当前请求的Host,scheme(?),端口和路径创建各种请求头。
可以通过下列参数来控制不同的请求头的产生(默认为true):
spring.cloud.gateway.x-forwarded.for-enabled
spring.cloud.gateway.x-forwarded.host-enabled
spring.cloud.gateway.x-forwarded.port-enabled
spring.cloud.gateway.x-forwarded.proto-enabled
spring.cloud.gateway.x-forwarded.prefix-enabled
可以通过以下布尔属性(默认为true)控制追加多个请求头:
spring.cloud.gateway.x-forwarded.for-append
spring.cloud.gateway.x-forwarded.host-append
spring.cloud.gateway.x-forwarded.port-append
spring.cloud.gateway.x-forwarded.proto-append
spring.cloud.gateway.x-forwarded.prefix-append
TLS和SSL
Spring Cloud Gateway可以按照通常的Spring Server配置来监听HTTPS的请求。参见如下示例:
示例61:application.yml
1 | server: |
可以将网关路由路由到HTTP和HTTPS后端。如果要路由到HTTPS后端,可以使用以下配置使网关信任下游的所有证书:
示例62:application.yml
1 | spring: |
生产环境不适合使用不安全的信任管理器。对于生产部署,可以使用以下配置使网管信任下游的一组证书:
示例63:application.yml
1 | spring: |
如果Spring Cloud gateway没有配置授信的证书,将会使用默认的信任存储(可以通过覆盖javax.net.ssl.trustStore
属性来覆盖默认配置)。
TLS 握手
网关维护了一个客户端池用来路由到后端。当通过HTTPS进行通信时,客户端会初始化一个TLS握手,顺带一系列的超时配置。可以通过以下配置配置这些超时:
示例64:application.yml
1 | spring: |
配置
Spring Cloud Gateway由一系列的RouteDefinitionLocator实例驱动。
示例65:application.yml
1 | public interface RouteDefinitionLocator { |
默认情况下,PropertiesRouteDefinitionLocator
通过Spring Boot的@ConfigurationPtoperties
机制加载配置。
前面的配置示例都使用位置参数而不是命名参数的快捷方式表示法。以下两个示例等效:
示例66:application.yml
1 | spring: |
对于网管的一些使用场景,属性文件已经足够了。但某些生产场景下,受益于从外部加载配置(例如数据库)。未来的里程碑版本中,RouteDefinitionLocator将基于Spring Data Repositories实现(比如Redis,MongoDB和Cassandra)。
路由元数据配置
可以通过元数据为每个路由配置一些额外的参数。
示例67 application.yml
1 | spring: |
接着就可以从exchange中获取这些元数据属性:
1 | Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR); |
Http 超时配置
可以针对所有的也可以针对特定的路由配置Http超时(响应和连接)。
全局超时
如果要配置全局超时:
connect-timeout
需要以毫秒为单位配置
response-time
需要以java.time.Duration为单位配置。
全局HTTP超时配置
1 | spring: |
单路由超时
如果要针对特定的路由配置超时
connect-timeout
需要以毫秒为单位配置
response-timeout
需要以毫秒为单位配置。
单路由超时配置-配置文件
1 | id: per_route_timeouts |
单路由超时配置-Java代码
1 | import static org.springframework.cloud.gateway.support.RouteMetadataUtils.CONNECT_TIMEOUT_ATTR; |
流畅的Java路由API
为了允许在Java中进行简单的配置,RouteLocatorBuilder Bean包含了一个流畅的API。下面的例子显示了它是如何工作的:
示例68:GatewaySampleApplication.java
1 | // static imports from GatewayFilters and RoutePredicates |
此样式还自持更多的自定义断言。RouteDefinitionLocator Bean定义的断言通过逻辑 ‘和’组合在一起。借助使用Java API,可以在断言上使用and(),or()和negate()运算符。
DiscoveryClient Route Definition Locator
可以根据DiscoveryClient兼容的服务注册中心来为网关创建路由。为此,将配置spring.cloud.gateway.discovery.locator.enable
设置为true,并确保类路径上存在一个DiscoveryClient的实现(例如,Netflix Eureka,Consul或者Zookeeper)。
为DiscoverClient路由配置断言和过滤器
默认情况下,网关会为DiscoveryClient创建的路由定义单个断言和过滤器。
默认的断言是一个路径断言。它的模式是/serviceId/*
,其中serviceId是DiscoveryClient中的服务ID。
默认的过滤器是一个重写路径过滤器。它会将serviceId/(?<remaining>.*)
中的部分,替换为/${remaining}
。这个过滤器将会在请求发送至下游的服务之前将服务ID剥离。
如果想要自定义DiscoveryClient使用的断言或者过滤器,设置spring.cloud.gateway.discovery.locator.predicates[x]
和spring.cloud.gateway.discovery.locator.filters[y]
。如果需要保留上出的默认功能,确保包含了默认的断言和过滤器。
示例69:application.yml
1 | spring.cloud.gateway.discovery.locator.predicates[0].name: Path |
Reactor Netty Access Logs
配置-Dreactor.netty.http.server.accessLogEnabled=true
为true,可以打开Reactor Netty access logs.可以配置日志系统处理一个单独的日志文件。
示例70:application.yml
1 | <appender name="accessLog" class="ch.qos.logback.core.FileAppender"> |
CORS配置
可以配置网关来控制CORS行为。“全局”CORS配置是一个指向Spring 框架的URL映射表。
示例71:application.yml
1 | spring: |
在上一个示例中,来自docs.spring.io的GET请求都被允许放行。
若要为某些网关路由谓词未处理的请求提供相同的 CORS 配置,可以将属性spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping
设置为true。当场是支持CORS预检请求并且因为方法是OPTIONS导致路由断言匹配失败是,非常有用。
Actuator API
/gateway执行器允许监控Spring Cloug Gateway并且与之交互。要想远程访问,必须启动端点,并将其通过HTTP或者JMX对外暴露。
示例72:application.yml
1 | management.endpoint.gateway.enabled=true # default value |
Verbose Actuator Format
一种新的,更详细的格式已经到Spring Cloud Gateway中。它向每个路由添加更多详细信息,允许查看与每个路由关联的断言和过滤器以及任何可用的配置。下面的示例配置 /actutor/gateway/routes:
1 | [ |
这个功能默认是开启的,如果需要关掉的话,按照如下配置:
示例73:application.yml
1 | spring.cloud.gateway.actuator.verbose.enabled=false |
这个在将来的发行版中,会默认设置为true。
检索路由过滤器
全局过滤器
向地址/actuator/gateway/globalfilters
发送一个get请求,就能检索到应用于所有路由的全局过滤器。接口的响应和下面的类似:
1 | { |
响应中包括每个全局路由器的详情。对每个全局路由器,返回一个该路由器的String表示法和它在过滤器链中的顺序。
路由过滤器
向接口/actuator/gateway/routerfilters
发送一个get请求,就ikeyi减速到应用于路由的网管过滤器工厂。响应和下面的类似:
1 | { |
响应中包含任何应用于特定路由器的网关过滤器工厂的详细信息。对于每个工厂,都有相应对象的字符串表示形式(例如,[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object])。请注意,null 值是由于终结点控制器的未完成实现造成的,因为它尝试设置筛选器链中对象的顺序,这不适用于 GatewayFilter 工厂对象。
刷新路由缓存
发起一个POST /actuator/gateway/refresh
请求,就能刷新路由缓存。成功发起这个请求得到的返回为空,返回码为200。
检索网关路由
发起一个GET /actuator/gateway/routes
请求,就inenghuoqu到网关中定义的路由信息。返回的结果类似于如下:
1 | [{ |
响应中包好了所有网关中所有路由的详细信息。下表描述了返回中的每个字段的含义:
路径 | 类型 | 描述 |
---|---|---|
route_id | String | 路由ID |
route_object.predicate | Object | 路由断言 |
route_object.filters | Array | 网关的网管路由器列表 |
order | Number | 路由的顺序 |
获取特定路由的信息
发起一个GET /actuator/gateway/routes/{id}
请求来获取指定路由的详细信息。返回结果类似于下文:
1 | { |
字段释义见下表:
路径 | 类别 | 描述 |
---|---|---|
id | String | 路由id |
predicates | Array | 路由断言列表。数组中的每项包括了断言的名称和参数 |
filters | Array | 指定路由的过滤器集合 |
uri | String | 路由的目的URI |
order | Number | 路由的顺序 |
创建和删除指定的路由
创建路由:POST /gateway/routes/{route_id_to_create}
,请求体参考这里。
删除路由:DELETE /gateway/routes/{route_id_to_delete}
。
回顾:所有终结点的列表
下表描述了Spring Cloud Gateway的所有端点(剥离了前缀/actuator/gateway):
ID | HTTP方法 | 描述 |
---|---|---|
globalfilters | GET | 获取路由的所有全局过滤器 |
routefilters | GET | 获取指定路由的所有网关过滤器工厂 |
refresh | POST | 清理路由缓存 |
routes | GET | 获取网关中定义的路由列表 |
routes/{id} | GET | 获取指定路由的详情 |
routes/{id} | POST | 创建一个新路由 |
routes/{id} | DELETE | 删除指定的路由 |
问题定位
日志级别
以下的日志在DEBUG和TRACE级别可能包含一些有价值的故障排除信息:
org.springframework.cloud.gateway
org.springframework.http.server.reactive
org.springframework.web.reactive
org.springframework.boot.autoconfigure.web
reactor.netty
redisratelimiter
”窃听“
反应式Netty HttpClient和HttpServer可以启用”窃听“。当reactor.netty 日志级别设置为DEBUG或TRACE时,它记录一些通过网络发送和接受的请求头和请求体。要启用”窃听“,要设置set spring.cloud.gateway.httpserver.wiretap=true
或者对HttpServer和HttpClient来书,设置spring.cloud.gateway.httpclient.wiretap=true
。
开发者指南
编写自定义路由断言工厂
自定义路由断言工厂需要实现RoutePredicateFactory类。有一个名为AbstractRoutePredicateFactory
的抽象类可以被扩展。
MyRoutePredicateFactory.java
1 | public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<HeaderRoutePredicateFactory.Config> { |
自定义网关过滤器工厂
要自定义一个网关过滤器工厂,可以实现GatewayFilterFactory
接口,或者扩展抽象类AbstractGatewayFilterFactory
。
示例74:PreGatewayFilterFactory.java
1 | public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> { |
PostGatewayFilterFactory.java
1 | public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> { |
在配置中命名自定义过滤器和引用
自定义过滤器类名应该以GatewayFilterFactory结尾。
例如,如果配置中要引用一个名为Something
的过滤器,那么这个过滤器的类名一定要是SomethingGatewayFilterFactory
。
自定义全局过滤器
必须实现GlobalFilter
接口。这个过滤器会应用到所有的请求上。
下面的样例展示了如何设置全局”前置“和”后置“过滤器:
1 |
|
使用Spring MVC或者Webflux构件一个简单的网关
Spring Cloud Gateway提供了一个使用的对象,称之为ProxyExchange。可以在常规的Spring Web Handler中使用它作为方法参数。它支持通过镜像HTTP谓词的方法同下游进行HTTP交换。使用MVC的话,它还支持通过forward()方法转发到本地的handler上。要使用代理交换,请将正确的模块包括在类路径中(spring-cloud-gateway-mvc 或 spring-Cloud-gateway-webflux)。
下面的MVC例子代理了请求/test
到下游的远端服务器:
1 |
|
下面的例子使用Webflux完成了同样的功能:
1 |
|
ProxyExchange提供的简便方法是Handler方法可以发现和增强传入请求的URI路径。例如,你可能希望提取路径的末尾元素,以便将他们传递到下游:@GetMapping("/proxy/path/**")
。
1 |
|
Spring MVC 和 Webflux 的所有功能都可用于网关Handler方法。因此,可以注入请求头和查询参数,例如,还可以使用映射注释中的声明约束传入请求。更多关于功能@RequestMapping,请参阅 Spring MVC 中有关文档。
可以通过ProxyExchange的header方法,将请求头添加到下游的响应上。
还可以通过添加一个映射器到get方法(或者其他方法)来操作响应的请求头(或者响应中的其他属性)。这个映射器是一个函数,它使用传入请求的ResponseEntity作为参数,并将它转换为传出响应。
”敏感“的请求头(默认情况下,cookie和鉴权)和代理请求头(xforwarded-×)是享受最高等的支持的。
配置属性
参见附录