一、快速开始
路由过滤器允许修改传⼊的HTTP请求和传出的HTTP响应。Spring Cloud Gateway包括了许多内置的GatewayFilter Factories。
filters一般和predicates一起配合来使用。当满足xxx条件,即执行某filter的逻辑。
可以通过配置文件和代码两种方式,来配置routes
下面是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();
}
配置的写法略,见下面的示例
二、基本原理
GatewayFilterFactory的作用是:生成GatewayFilter。
GatewayFilter的作用是:对请求或者返回报文进行处理。
以下是一段源码,该GatewayFilter的作用就是添加请求头,而这个请求头就是在配置文件里面定义的。
public class AddRequestHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
ServerHttpRequest request = exchange.getRequest().mutate()
.headers(httpHeaders -> httpHeaders.add(config.getName(), value)).build();
return chain.filter(exchange.mutate().request(request).build());
}
@Override
public String toString() {
return filterToStringCreator(AddRequestHeaderGatewayFilterFactory.this)
.append(config.getName(), config.getValue()).toString();
}
};
}
}
GateWayFilterFactory的本质就是:针对配置进行解析,为指定的路由,添加Filter,以便对请求报文进行处理。
三、过滤器示例
3.1 The AddRequestHeader GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
predicates:
- Path=/red/{
segment}
filters:
- AddRequestHeader=X-Request-Red, Blue-{
segment}
添加头信息:X-Request-Red,value为Blue-{segment},segment是路径里面带的信息
3.2 The AddRequestParameter GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: https://example.org
predicates:
- Host: {
segment}.myhost.org
filters:
- AddRequestParameter=foo, bar-{
segment}
添加参数name=foo,value=bar-{segment}
3.3 The AddResponseHeader GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: add_response_header_route
uri: https://example.org
predicates:
- Host: {
segment}.myhost.org
filters:
- AddResponseHeader=foo, bar-{
segment}
添加返回头信息 name=foo,value=bar-{segment}
3.4 The DedupeResponseHeader GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: dedupe_response_header_route
uri: https://example.org
filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
当网关CROS和下游响应头都有Access-Control-Allow-Credentials 和 Access-Control-Allow-Origin时,将删除重复的响应头
3.5 Spring Cloud CircuitBreaker GatewayFilter Factory
使⽤ Spring Cloud CircuitBreaker的API将⽹关路由包装到断路器中。Spring Cloud CircuitBreaker ⽀持多种库⽤于Spring Cloud Gateway。⽐如Resilience4J。
要启⽤Spring Cloud CircuitBreaker过滤器,你需要引⼊spring-cloud-starter-circuitbreaker-reactor-resilience4j ,如下是配置示例
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
RewritePath 表示将 /consumingServiceEndpoint 路径在请求前重写为 /backingServiceEndpoint
fallbackUri,即熔断以后的请求,需要跳到这个路径。这个路径可以由网关本身提供。例如:网关可以提供一个Controller,路径为/inCaseOfFailureUseThis
下面是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();
}
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路径。/fallback路径正好是由另一个服务(http://localhost:9994)提供
3.6 The FallbackHeaders GatewayFilter Factory
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
The FallbackHeaders GatewayFilter Factory
在该例中,在运⾏circuit breaker 发生异常后,请求将被转发到 http://localhost:9994 的 /fallback 中。异常类型、消息等通过 FallbackHeaders 过滤器添加到请求头中。
通过设置下面列出的参数值,可以在配置中覆盖headers的名称。
executionExceptionTypeHeaderName ("Execution-Exception-Type")
executionExceptionMessageHeaderName ("Execution-Exception-Message")
rootCauseExceptionTypeHeaderName ("Root-Cause-Exception-Type")
rootCauseExceptionMessageHeaderName ("Root-Cause-Exception-Message")
3.7 The MapRequestHeader GatewayFilter Factory
接收两个参数,分别是fromHeader 和 toHeader。它会创建⼀个新的header( toHeader ),并从 fromHeader 中提取值。如果输入的header不存在,该过滤器不会执⾏。如果新的header已经存在,那么它将被追加新值。如下所示:
spring:
cloud:
gateway:
routes:
- id: map_request_header_route
uri: https://example.org
filters:
- MapRequestHeader=Blue, X-Request-Red
该示例会将 X-Request-Red: 头添加到下游请求中,值为传⼊的HTTP请求 Blue 值。
3.8 The PrefixPath GatewayFilter Factory
接收⼀个参数 prefix
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- PrefixPath=/mypath
该示例将在所有匹配请求路径前加上前缀 /mypath ,因此请求 /hello 时,将发送到 /mypath/hello 中。
3.9 The PreserveHostHeader GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: preserve_host_route
uri: https://example.org
filters:
- PreserveHostHeader
该过滤⼯⼚没有接收参数。设置了该Filter后,GatewayFilter将不使⽤由HTTP客户端确定的host header ,⽽是发送原始host header。
例如,网关的host header是localhost:8080,下游服务的host header是192.168.1.11:8080,这里返回的是网关的host,即localhost:8080
3.10 The RequestRateLimiter GatewayFilter Factory
该过滤器使⽤ RateLimiter 来实现是否允许继续执⾏该请求。如果不允许继续执⾏,返回 HTTP 429 - Too
Many Requests (默认情况下)。
该过滤器可以配置⼀个可选的 keyResolver 参数和rate limiter参数。
keyResolver 是 KeyResolver 的⼀个实现类,在配置中,按名称使⽤SpEL引⽤bean。#{@myKeyResolver}是引
⽤名为’myKeyResolver’的bean的SpEL表达式。
public interface KeyResolver {
Mono<String> resolve(ServerWebExchange exchange);
}
KeyResolver 接⼝允许使⽤可插拔策略来派⽣限制请求的key。在未来的⾥程碑版本中,将有⼀些 KeyResolver实现。
KeyResolver 的默认实现是 PrincipalNameKeyResolver ,它从 ServerWebExchange 检索 Principal 并调⽤ Principal.getName()。
默认情况下,如果 KeyResolver 没有获取到key,请求将被拒绝。您可以通过如下设置来调整:
spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key (true or false)
spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code
RequestRateLimiter 不能使⽤“shortcut”来配置,如下配置⽆效:
# INVALID SHORTCUT CONFIGURATION
spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2, #{@userkeyresolver}
3.10.1 Redis RateLimiter(演示)
Redis实现基于Stripe。它需要引⼊ spring-boot-starter-data-redis-reactive 依赖。
使⽤的算法是Token Bucket Algorithm。
redis-rate-limiter.replenishRate 配置是在不丢弃任何请求的情况下,你允许⽤户每秒执⾏多少请求。这是令牌桶的填充速率。
redis-rate-limiter.burstCapacity 配置是允许⽤户在⼀秒内执⾏的最⼤请求数。这是令牌桶可以保存的令牌数。将此值设置为0将阻⽌所有请求。
redis-rate-limiter.requestedTokens 配置⼀个请求所需要的令牌数。每个请求从令牌桶提取的令牌数,默认为1。
通过在 replenishRate 和 burstCapacity 中设置相同的值来实现稳定的速率。可通过设置 burstCapacity ⾼于 replenishRate 来允许临时突发流量。在这种情况下,限流器需要在两次突发之间留出⼀段时间(根据 replenishRate ),因为连续两次突发将导致请求丢失 (HTTP 429 - Too Many Requests)。如下列表配置了⼀个 redis-rate-limiter :
⽐如: replenishRate=1 、 requestedTokens=60 和 burstCapacity=60 将限制为 1 request/min 。
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
配置⼀个KeyResolver
@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}
这定义了每个⽤户10个请求的限制。允许20个突发,但下⼀秒只有10个请求可⽤。 KeyResolver 是⼀个简单的获
取user请求参数的⼯具(注意:不建议⽤于⽣产)。
限流器也可以定义为 RateLimiter 接⼝的实现 bean。在配置中,按名称使⽤SpEL引⽤bean。 #
{@myRateLimiter} 是引⽤名为 myRateLimiter 的bean的SpEL表达式。
spring:
cloud:
gateway:
routes:
- id: requestratelimiter_route
uri: https://example.org
filters:
- name: RequestRateLimiter
args:
rate-limiter: "#{@myRateLimiter}"
key-resolver: "#{@userKeyResolver}"
3.11 The RedirectTo GatewayFilter Factory
接收两个参数: status 和 url 。
status 是300类重定向HTTP码,如301。该 url 应该是⼀个有效的URL,值是 Location header的值。
对于相对路径,应该使⽤ uri: no://op 作为路由定义
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- RedirectTo=302, https://acme.org
该例将发送⼀个302重定向状态码到 Location:https://acme.org
3.12 The RemoveRequestHeader GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: removerequestheader_route
uri: https://example.org
filters:
- RemoveRequestHeader=X-Request-Foo
删除请求header:X-Request-Foo
3.13 RemoveResponseHeader GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: removeresponseheader_route
uri: https://example.org
filters:
- RemoveResponseHeader=X-Response-Foo
删除返回header:X-Response-Foo
3.14 The RemoveRequestParameter GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: removerequestparameter_route
uri: https://example.org
filters:
- RemoveRequestParameter=red
删除请求参数
3.15 The RewritePath GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: rewritepath_route
uri: https://example.org
predicates:
- Path=/red/**
filters:
- RewritePath=/red(?<segment>/?.*), $\{
segment}
对于 /red/blue 请求路径,将在发送到下游之前替换为 /blue 。因为YAML规范,要把 $ 替换为 $\
3.16 RewriteLocationResponseHeader GatewayFilter Factory
该过滤器修改 Location 响应头的值,经常⽤于去掉⼀些敏感信息。接收参数分别是:
stripVersionMode, locationHeaderName, hostValue, protocolsRegex
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 的header值。
protocolsRegex 参数是⼀个有效的正则字符串。如果不匹配,则过滤器不执⾏。默认值为http | https | ftp | ftps
3.17 The RewriteResponseHeader GatewayFilter Factory
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 。您必须使⽤ $\ 代替 $
3.18 The SaveSession GatewayFilter Factory
SaveSession GatewayFilter Factory将调⽤转发到下游之前强制执⾏ WebSession::save 操作。这在使⽤ Spring
Session 之类时特别有⽤,需要确保会话状态在进⾏转发调⽤之前已保存
spring:
cloud:
gateway:
routes:
- id: save_session
uri: https://example.org
predicates:
- Path=/foo/**
filters:
- SaveSession
如果你希望要将Spring Security与Spring Session集成,并要确保安全信息都传到下游,这样做将是很重要的
3.19 The SecureHeaders GatewayFilter Factory
SecureHeaders GatewayFilter Factory在response响应中添加了许多头。
添加了以下的头(默认值)
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-down-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
3.20 The SetPath GatewayFilter Factory
SetPath GatewayFilter Factory 采⽤⼀个 template 路径参数。它提供了⼀种简单的⽅法,通过允许路径的模板化
segments来操作请求路径。使⽤Spring Framework中的URI模板,允许多个匹配segments
spring:
cloud:
gateway:
routes:
- id: setpath_route
uri: https://example.org
predicates:
- Path=/red/{
segment}
filters:
- SetPath=/{
segment}
如上所示:请求 /red/blue ,将在请求下游时将路径设置为 /blue
3.21 The SetRequestHeader GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: setrequestheader_route
uri: https://example.org
filters:
- SetRequestHeader=X-Request-Red, Blue
该GatewayFilter将会使⽤给定的name替换所有的header,⽽不是添加。因此会将请求头从 X-Request-
Red:1234 设置为 X-Request-Red:Blue 。
SetRequestHeader 允许使⽤path或者host的URI变量
spring:
cloud:
gateway:
routes:
- id: setrequestheader_route
uri: https://example.org
predicates:
- Host: {
segment}.myhost.org
filters:
- SetRequestHeader=foo, bar-{
segment}
3.22 The SetResponseHeader GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: setresponseheader_route
uri: https://example.org
filters:
- SetResponseHeader=X-Response-Red, Blue
该GatewayFilter将会使⽤给定的name替换所有的header,⽽不是添加。下游响应的头 X-Response-Red:1234
将会替换成 X-Response-Red:Blue 。
SetResponseHeader 也使⽤path或者host的URI变量
spring:
cloud:
gateway:
routes:
- id: setresponseheader_route
uri: https://example.org
predicates:
- Host: {
segment}.myhost.org
filters:
- SetResponseHeader=foo, bar-{
segment}
3.23 The SetStatus GatewayFilter Factory
接收⼀个参数 status ,必须是⼀个可⽤的Spring HttpStatus 值,可⽤是整数或者枚举字符串
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 status响应头设置为401。
使⽤ SetStatus 可以在响应中返回代理请求中的原始Http 状态码。如下配置,将header添加到响应中
spring:
cloud:
gateway:
set-status:
original-status-header-name: original-http-status
3.24 The StripPrefix GatewayFilter Factory
接收⼀个 parts 参数。 parts参数指示在将请求发送到下游之前,要从请求中去除的路径中的节数
spring:
cloud:
gateway:
routes:
- id: nameRoot
uri: https://nameservice
predicates:
- Path=/name/**
filters:
- StripPrefix=2
该示例表示当⽹关发送 /name/blue/red 请求时,实际向下游请求的地址是 nameservice/red
3.25 The Retry GatewayFilter Factory
Retry GatewayFilter Factory使⽤了reactor-addons 的retry组件进⾏重试,⽀持以下参数:
retries:应尝试的重试次数
statuses:应尝试的HTTP状态码
methods:应尝试的HTTP⽅法
series:应尝试的series状态码, org.springframework.http.HttpStatus.Series
exceptions:应尝试的异常列表
backoff:配置指数退避重试。根据 firstBackoff * (factor ^ n) 进⾏指数重试, maxBackoff 限制最⼤
退避重试,如果 basedOnPreviousValue 为true,则退避指数计算使⽤ prevBackoff * factor 。
Retry 过滤器默认值配置如下:
retries: 3次
series: 5XX series
methods:GET ⽅法
exceptions:IOException 和 TimeoutException
backoff: disabled
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
当重试过滤器与任何带body的HTTP请求使⽤时,body会被缓存。body被缓存在请求定义的的
ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR 中,对象类型是: org.springframework.core.io.buffer.DataBuffer
3.26 The RequestSize GatewayFilter Factory
当请求⼤⼩⼤于允许的限制时,RequestSize GatewayFilter Factory可以限制请求不到达下游服务。过滤器以
RequestSize作为参数,这是定义请求的允许⼤⼩限制(以字节为单位)
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 ,
并带有额外的header errorMessage
errorMessage:
Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB
3.27 The SetRequestHost GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: set_request_host_header_route
uri: http://localhost:8080/headers
predicates:
- Path=/headers
filters:
- name: SetRequestHost
args:
host: example.org
该示例表示使⽤ example.org 代替host头的值
3.28 Modify a Request Body GatewayFilter Factory
此过滤器可⽤于在请求主体被⽹关发送到下游之前对其进⾏修改
@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.29 Modify a Response Body GatewayFilter Factory
此过滤器可⽤于在将响应正⽂发送回客户端之前对其进⾏修改
@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();
}
四、设置 Default Filters
可以使⽤ spring.cloud.gateway.default-filters 作为所有路由的过滤器。该配置接收⼀个filter列表,如下
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Red, Default-Blue
- PrefixPath=/httpbin
五、问题
-
问题1:如果routes下面只有filters,没有predicates会是什么效果?该filter是拦截全部请求,还是都不拦截?
-
问题2:predicates和filters是复数,意味着可以配置多个predicates和多个filters,怎么配置?
下面示例展示了一个两个filter的配置,用了熔断和重写路径Filter
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