过滤器工厂详解

这一节来探讨Spring Cloud Gateway内置的Filter工厂。

技巧

  • 断点打在 org.springframework.cloud.gateway.filter.NettyRoutingFilter#filter ,就可以调试Gateway转发的具体细节了。
  • 添加如下配置,可观察到一些请求细节:
    logging:
      level:
        org.springframework.cloud.gateway: trace
        org.springframework.http.server.reactive: debug
        org.springframework.web.reactive: debug
        reactor.ipc.netty: debug

1 AddRequestHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: add_request_header_route
          uri: https://example.org
          filters:
            - AddRequestHeader=X-Request-Foo, Bar

为原始请求添加名为 X-Request-Foo ,值为 Bar 的请求头。

2 AddRequestParameter GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: add_request_parameter_route
          uri: https://example.org
          filters:
            - AddRequestParameter=foo, bar

为原始请求添加请求参数 foo=bar

3 AddResponseHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: add_response_header_route
          uri: https://example.org
          filters:
            - AddResponseHeader=X-Response-Foo, Bar

添加名为 X-Request-Foo ,值为 Bar 的响应头。

4 DedupeResponseHeader GatewayFilter Factory

TIPS

Spring Cloud Greenwich SR2提供的新特性,低于这个版本无法使用。

强烈建议
阅读一下类org.springframework.cloud.gateway.filter.factory.DedupeResponseHeaderGatewayFilterFactory上的注释,比官方文档写得还好。

spring:
  cloud:
    gateway:
      routes:
        - id: dedupe_response_header_route
          uri: https://example.org
          filters:
            - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_FIRST

剔除重复的响应头。 举个例子: 我们在Gateway以及微服务上都设置了CORS(解决跨域)header,如果不做任何配置,请求 - 网关 - 微服务,获得的响应就是这样的:

Access-Control-Allow-Credentials: true, true
Access-Control-Allow-Origin: https://musk.mars, https://musk.mars

也就是Header重复了。要想把这两个Header去重,只需设置成如下即可。

filters:
  - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin

也就是说,想要去重的Header如果有多个,用空格分隔即可; 去重策略:

RETAIN_FIRST: 默认值,保留第一个值
RETAIN_LAST: 保留最后一个值
RETAIN_UNIQUE: 保留所有唯一值,以它们第一次出现的顺序保留

5 Hystrix GatewayFilter Factory

TIPS

Hystrix是Spring
Cloud第一代中的容错组件,不过已经进入维护模式(相关文章:Spring Cloud Netflix项目进入维护模式之我见
),未来,Hystrix会被Spring Cloud移除掉,取而代之的是Alibaba Sentinel/Resilience4J

所以本文不做详细探讨了,但Gateway整合Hystrix其实包含了很多姿势。请感兴趣的同学自行前往官方文档了解详情:https://cloud.spring.io/spring-cloud-static/Greenwich.SR2/single/spring-cloud.html#hystrix

spring:
  cloud:
    gateway:
      routes:
        - id: hystrix_route
          uri: https://example.org
          filters:
            - Hystrix=myCommandName

6 FallbackHeaders GatewayFilter Factory

TIPS

也是对Hystrix的支持,不做详细探讨了,请感兴趣的同学自行前往官方文档了解详情:https://cloud.spring.io/spring-cloud-static/Greenwich.SR2/single/spring-cloud.html#fallback-headers

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

7 MapRequestHeader GatewayFilter Factory

TIPS

Hoxton开始支持

spring:
  cloud:
    gateway:
      routes:
        - id: map_request_header_route
          uri: https://example.org
          filters:
            - MapRequestHeader=Bar, X-Request-Foo

获取名为Bar的header的值,并设置为X-Request-Foo的值,传给后端微服务。举个例子:获取到Header Bar=aaa,那么转发到后端微服务时,就会传递Header
X-Request-Foo=aaa。

7 PrefixPath GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: prefixpath_route
          uri: https://example.org
          filters:
            - PrefixPath=/mypath

为匹配的路由添加前缀。例如:访问${GATEWAY_URL}/hello 会转发到https://example.org/mypath/hello

9 PreserveHostHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: preserve_host_route
          uri: https://example.org
          filters:
            - PreserveHostHeader

如果不设置,那么名为 Host 的Header由Http
Client控制;如果设置了,那么会设置一个请求属性(preserveHostHeader=true),路由过滤器会检查从而去判断是否要发送原始的、名为Host的Header。

10 RequestRateLimiter GatewayFilter Factory

TIPS

在文章《 限流手把手教程

中有详细说明。也可阅读官方文档 https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.0.M3/reference/html/#requestratelimiter-gatewayfilter-factory

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

11 RedirectTo GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: prefixpath_route
          uri: https://example.org
          filters:
            # 配置成HTTP状态码, URL的形式
            - RedirectTo=302, http://www.itmuch.com
  • HTTP状态码应该是HTTP状态码300序列,例如301
  • URL必须是合法的URL,并且该值会作为名为 Location 的Header。 上面配置表达的意思是: ${GATEWAY_URL}/hello
    会重定向到 https://ecme.org/hello ,并且携带一个 Location:http://www.itmuch.com 的Header。

12 RemoveHopByHopHeadersFilter GatewayFilter Factory

spring.cloud.gateway.filter.remove-hop-by-hop.headers: Connection,Keep-Alive

移除转发请求的Header,多个用 ,
分隔。默认情况下,移除如下Header。这些Header是由 IETF
组织规定的。

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

13 RemoveRequestHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: removerequestheader_route
          uri: https://example.org
          filters:
            - RemoveRequestHeader=X-Request-Foo

为原始请求删除名为 X-Request-Foo 的请求头。

14 RemoveResponseHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: removeresponseheader_route
          uri: https://example.org
          filters:
            - RemoveResponseHeader=X-Response-Foo

删除名为 X-Request-Foo 的响应头。

15 RemoveRequestParameter GatewayFilter Factory

TIPS

Hoxton开始支持

spring:
  cloud:
    gateway:
      routes:
        - id: removerequestparameter_route
          uri: https://example.org
          filters:
            - RemoveRequestParameter=foo

删除指定名称的参数。如上,可删除名为foo的参数。

16 RewritePath GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: rewritepath_route
          uri: https://example.org
          predicates:
            - Path=/foo/**
          filters:
            # 配置成原始路径正则, 重写后的路径的正则
            - RewritePath=/foo/(?\u003csegment
  .*), /$\\{segment}

重写请求路径。如上配置,访问 /foo/bar 会将路径改为/bar 再转发,也就是会转发到 https://example.org/bar
。需要注意的是,由于YAML语法,需用$\\ 替换 $

17 RewriteLocationResponseHeader GatewayFilter Factory

TIPS

Hoxton开始支持。这段文字稍微有点绕,建议参考这段配置,然后做个测试,并阅读下源码。其实还是比较简单的,就是一个重写名为 Location 的响应Header的过滤器工厂。

spring:
  cloud:
    gateway:
      routes:
        - id: rewritelocationresponseheader_route
          uri: http://example.org
          filters:
            - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, ,

该过滤器工厂用于修改的响应的名为Location 的参数,它接收三个参数:stripVersionMode、locationHeaderName、hostValue。 如上配置,可达到的效果:
例如: POST api.example.com/some/object/name ,那么,如果响应的名为 Location
的header的值是 object-service.prod.example.net/v2/some/object/id
的话,会被重写为 api.example.com/some/object/id. 其中,stripVersionMode的取值有:

  • NEVER_STRIP :即使原始请求路径不包含任何版本,也不会剥离版本
  • AS_IN_REQUEST :仅当原始请求路径不包含版本时,版本才会被剥离
  • ALWAYS_STRIP :即使原始请求路径包含版本,也会删除版本 hostValue可为空,如果不为空的话,那么将用于替换 host:port 响应 Location
    头的一部分。如果为空,则使用请求的名为 Host 的header的值。

18 RewriteResponseHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: rewriteresponseheader_route
          uri: https://example.org
          filters:
            - RewriteResponseHeader=X-Response-Foo, password=[^\u0026]+, password=***

如果名为 X-Response-Foo 的响应头的内容是/42?user=ford\u0026password=omg!what\u0026flag=true
,则会被修改为/42?user=ford\u0026password=***\u0026flag=true

19 SaveSession GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: save_session
          uri: https://example.org
          predicates:
            - Path=/foo/**
          filters:
            - SaveSession

在转发到后端微服务请求之前,强制执行 WebSession::save 操作。用在那种像 Spring Session
延迟数据存储(笔者注:数据不是立刻持久化)的,并希望在请求转发前确保session状态保存情况。 如果你将Spring SecutirySpring Session
集成使用,并想确保安全信息都传到下游机器,你就需要配置这个filter。

20 SecureHeaders GatewayFilter Factory

添加一系列起安全作用的响应头。Spring Cloud
Gateway参考了这篇博客的建议:https://blog.appcanary.com/2017/http-security-headers.html
默认会添加如下Header(包括值):

  • 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 \u0027self\u0027 https:; font-src \u0027self\u0027 https: data:; img-src \u0027self\u0027 https: data:; object-src \u0027none\u0027; script-src https:; style-src \u0027self\u0027 https: \u0027unsafe-inline\u0027
  • X-Download-Options:noopen
  • X-Permitted-Cross-Domain-Policies:none
    如果你想修改这些Header的值,可使用如下配置: 前缀:spring.cloud.gateway.filter.secure-headers
    上面的header对应的后缀:
  • 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.xss-protection-header: 你想要的值
    如果想禁用某些Header,可使用如下配置:spring.cloud.gateway.filter.secure-headers.disable ,多个用 ,
    分隔。例如:spring.cloud.gateway.filter.secure-headers.disable=frame-options,download-options

21 SetPath GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: setpath_route
          uri: https://example.org
          predicates:
            - Path=/foo/{segment}
          filters:
            - SetPath=/{segment}

采用路径template参数,通过请求路径的片段的模板化,来达到操作修改路径的母的,运行多个路径片段模板化。 如上配置,访问${GATEWAY_PATH}/foo/bar
,则对于后端微服务的路径会修改为 /bar

22 SetRequestHeader GatewayFilter Factory

TIPS

Hoxton版本开始支持。

spring:
  cloud:
    gateway:
      routes:
        - id: setrequestheader_route
          uri: https://example.org
          filters:
            - SetRequestHeader=X-Request-Foo, Bar

将名为 X-Request-Foo 的header设置为Bar,再转发给后端微服务。高级一点的用法:

spring:
  cloud:
    gateway:
      routes:
        - id: setrequestheader_route
          uri: https://example.org
          predicates:
            - Host: { segment }.myhost.org
          filters:
            - SetRequestHeader=foo, bar-{segment}

访问 GATEWAY_URL/** 会转发到 https://example.org/**
,并且会读取request传递的名为Host的Header的值。如果是xxx.my.host.org ,则会设置Header foo=bar-xxx ,一次类推,segment是个占位符。

23 SetResponseHeader GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: setresponseheader_route
          uri: http://example.org
          filters:
            - SetResponseHeader=X-Response-Foo, Bar

如果后端服务响应带有名为 X-Response-Foo 的响应头,则将值改为替换成 Bar

24 SetStatus GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: setstatusstring_route
          uri: http://example.org
          filters:
            - SetStatus=BAD_REQUEST
        - id: setstatusint_route
          uri: http://example.org
          filters:
            - SetStatus=401

修改响应的状态码,值可以是数字,也可以是字符串。但一定要是Spring HttpStatus 枚举类中的值。如上配置,两种方式都可以返回HTTP状态码401。

25 StripPrefix GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: nameRoot
          uri: http://nameservice
          predicates:
            - Path=/name/**
          filters:
            - StripPrefix=2

数字表示要截断的路径的数量。如上配置,如果请求的路径为 /name/bar/foo ,则路径会修改为/foo ,也就是会截断2个路径。

26 Retry GatewayFilter Factory

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

针对不同的响应做重试,可配置如下参数:

  • retries: 重试次数
  • statuses: 需要重试的状态码,取值在 org.springframework.http.HttpStatus
  • methods: 需要重试的请求方法,取值在 org.springframework.http.HttpMethod
  • series: HTTP状态码系列,取值在 org.springframework.http.HttpStatus.Series

27 RequestSize GatewayFilter Factory

spring:
  cloud:
    gateway:
      routes:
        - id: request_size_route
      uri: http://localhost:8080/upload
      predicates:
        - Path=/upload
      filters:
        - name: RequestSize
          args:
            # 单位字节
            maxSize: 5000000

为后端服务设置收到的最大请求包大小。如果请求大小超过设置的值,则返回 413 Payload Too Large 。默认值是5M

28 Modify Request Body GatewayFilter Factory

TIPS

该过滤器处于 BETA 状态,未来API可能会变化,生产环境请慎用。 可用于在Gateway将请求发送给后端微服务之前,修改请求体内容。该过滤器只能通过代码配置,不支持在配置文件设置。示例:

@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;
  }
}

29 Modify Response Body GatewayFilter Factory

TIPS

该过滤器处于 BETA 状态,未来API可能会变化,生产环境请慎用。 可用于修改响应体内容。该过滤器只能通过代码配置,不支持在配置文件设置。示例:

@Bean
public RouteLocator routes(RouteLocatorBuilder builder){
    return builder.routes()
    .route(\"rewrite_response_upper\", r -
    r.host(\"*.rewriteresponseupper.org\")
    .filters(f-
    f.prefixPath(\"/httpbin\")
    \t\t.modifyResponseBody(String.class,String.class,
    \t\t(exchange,s)-
    Mono.just(s.toUpperCase()))).uri(uri)
    .build();
    }

30 Default Filters

spring:
  cloud:
    gateway:
      default-filters:
        - AddResponseHeader=X-Response-Default-Foo, Default-Bar
        - PrefixPath=/httpbin

如果你想为所有路由添加过滤器,可使用该属性。

参考文献

BAT架构师带你从零打造微服务项目