乐趣区

关于云计算:Spring-Cloud-Gateway实战之五内置filter

欢送拜访我的 GitHub

https://github.com/zq2599/blog_demos

内容:所有原创文章分类汇总及配套源码,波及 Java、Docker、Kubernetes、DevOPS 等;

本篇概览

  • 作为《Spring Cloud Gateway 实战》系列的第五篇,是时候理解过滤器 (filter) 的作用了,本篇咱们一起来理解 Spring Cloud Gateway 内置好的过滤器,真是品种繁多功能强大

    AddRequestHeader

  • AddRequestHeader 过滤器顾名思义,就是在申请头部增加指定的内容
  • 带有 predicate 的残缺配置:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
            - Path=/hello/**
          filters:
            - AddRequestHeader=x-request-foo, bar-config
  • 带有 predicate 的残缺动静配置:
[
    {
        "id": "path_route_addr",
        "uri": "http://127.0.0.1:8082",
        "predicates": [
            {
                "name": "Path",
                "args": {"pattern": "/hello/**"}
            }
        ],
        "filters": [
            {
                "name": "AddRequestHeader",
                "args": {
                    "name": "x-request-foo",
                    "value": "bar-dynamic"
                }
            }
        ]
    }
]
  • 实际效果:

AddRequestParameter

  • AddRequestParameter 过滤器顾名思义,就是增加申请参数
  • 配置如下,服务提供方收到的申请中会多一个参数,名为 foo,值为 bar-config:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
            - Path=/hello/**
          filters:
            - AddRequestParameter=foo, bar-config
  • 带有 predicate 的残缺动静配置:
[
    {
        "id": "path_route_addr",
        "uri": "http://127.0.0.1:8082",
        "predicates": [
            {
                "name": "Path",
                "args": {"pattern": "/hello/**"}
            }
        ],
        "filters": [
            {
                "name": "AddRequestParameter",
                "args": {
                    "name": "foo",
                    "value": "bar-dynamic"
                }
            }
        ]
    }
]
  • 实际效果:

AddResponseHeader

  • AddResponseHeader 过滤器就是在响应的 header 中增加参数
  • 配置如下,客户端收到的响应,其 header 中会多一个参数,名为 foo,值为 bar-config-response:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
          - Path=/hello/**
          filters:
          - AddResponseHeader=foo, bar-config-response
  • 带有 predicate 的残缺动静配置:
[
    {
        "id": "path_route_addr",
        "uri": "http://127.0.0.1:8082",
        "predicates": [
            {
                "name": "Path",
                "args": {"pattern": "/hello/**"}
            }
        ],
        "filters": [
            {
                "name": "AddResponseHeader",
                "args": {
                    "name": "foo",
                    "value": "bar-dynamic-response"
                }
            }
        ]
    }
]
  • 实际效果:

DedupeResponseHeader

  • 服务提供方返回的 response 的 header 中,如果有的 key 出线了多个 value(例如跨域场景下的 Access-Control-Allow-Origin),DedupeResponseHeader 过滤器能够将反复的 value 剔除调,剔除策略有三种:RETAIN_FIRST (保留第一个,默认), RETAIN_LAST(保留最初一个), RETAIN_UNIQUE(去重)
  • 配置如下,指定了两个 header key 的去重,策略是保留最初一个:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
          - Path=/hello/**
          filters:
          - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_LAST

DedupeResponseHeader

  • 服务提供方返回的 response 的 header 中,如果有的 key 出线了多个 value(例如跨域场景下的 Access-Control-Allow-Origin),DedupeResponseHeader 过滤器能够将反复的 value 剔除调,剔除策略有三种:RETAIN_FIRST (保留第一个,默认), RETAIN_LAST(保留最初一个), RETAIN_UNIQUE(去重)
  • 配置如下,指定了两个 header key 的去重,策略是保留最初一个:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
          - Path=/hello/**
          filters:
          - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_LAST

CircuitBreaker

  • CircuitBreaker 即断路器,咱们在独自的一篇中深刻体验这个弱小的性能吧

FallbackHeaders

  • FallbackHeaders 个别和 CircuitBreaker 配合应用,来看上面的配置,产生断路后,申请会被转发 FallbackHeaders 去解决,此时 FallbackHeaders 会在 header 中指定的 key 上增加异样信息:
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

MapRequestHeader

  • MapRequestHeader 用于 header 中的键值对复制,如下配置的意思是:如果申请 header 中有 <font color=”blue”>Blue</font> 就新增名为 <font color=”red”>X-Request-Red</font> 的 key,其值和 <font color=”blue”>Blue</font> 的值一样
  • 配置如下,指定了两个 header key 的去重,策略是保留最初一个:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
          - Path=/hello/**
          filters:
          - MapRequestHeader=Blue, X-Request-Red
  • 如下图,申请 header 中有 Blue:

  • 再看服务提供方的日志,显示 header 中多了 X -Request-Red:

  • 如果申请的 header 中曾经存在 <font color=”blue”>X-Request-Red</font> 会呈现什么状况呢?如下图,咱们把 <font color=”blue”>X-Request-Red</font> 写在申请 header 中:

  • 在服务提供方打断点,能够发现神奇的一幕,header 中的所有 key,对应的值其实都是汇合,只是大多数状况下汇合外面只有一个元素,而 MapRequestHeader 新增的元素会被放入这个汇合,不会影响原有内容:

PrefixPath

  • PrefixPath 很好了解,就是转发到服务提供者的时候,给 path 加前缀
  • 例如我这边服务提供者原始地址是 <font color=”blue”>http://127.0.0.1:8082/hello/str</font> 配置如下,如果我给网关配置 PrefixPath=hello,那么拜访网关的时候,申请门路中就不须要 <font color=”blue”>hello</font> 了,配置如下:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
          - Path=/str
          filters:
          - PrefixPath=/hello
  • 如下图,申请门路无需 <font color=”blue”>hello</font>:

PreserveHostHeader

  • PreserveHostHeader 在转发申请到服务提供者的时候,会保留 host 信息(否则就只能由 HTTP client 来决定了)
  • 先看不应用 PreserveHostHeader 的成果,如下图,服务提供者收到的申请 header 中的 host 就是网关配置的信息:

  • 加上 PreserveHostHeader 试试,如下图红框,是真正的 host 信息:

RequestRateLimiter

  • RequestRateLimiter 用于限流,波及内容较多,就放在独自的章节深入研究吧

RedirectTo

  • RedirectTo 的性能简略直白:跳转到指定地位,上面的配置中,uri 字段显著是一个有效的地址,但申请还是会被 RedirectTo 转发到指定地位去:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.1.1.1:11111
          predicates:
          - Path=/hello/**
          filters:
          - RedirectTo=302, http://127.0.0.1:8082/hello/str

RemoveRequestHeader

  • RemoveRequestHeader 很好了解,删除申请 header 中的指定值
  • 上面的配置会删除申请 header 中的 foo:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
          - Path=/hello/**
          filters:
          - RemoveRequestHeader=foo

RemoveResponseHeader

  • RemoveResponseHeader 删除响应 header 中的指定值
  • 上面的配置会删除响应 header 中的 foo:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
          - Path=/hello/**
          filters:
          - RemoveResponseHeader=foo

RemoveRequestParameter

  • RemoveRequestParameter 删除申请参数中的指定参数
  • 上面的配置会删除申请参数中的 foo:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
          - Path=/hello/**
          filters:
          - RemoveRequestParameter=foo1

RewritePath

  • RewritePath 十分实用,将申请参数中的门路做变换
  • 上面的配置会将 <font color=”blue”>/test/str</font> 转成 <font color=”blue”>/hello/str</font>:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
          - Path=/test/**
          filters:
          - RewritePath=/test/?(?<segment>.*), /hello/$\{segment}
  • 申请如下,可见 path 中的 test 会被网关批改成 hello,变成正确的申请门路:

RewriteLocationResponseHeader

  • RewriteLocationResponseHeader 用于改写 response 中的 location 信息
  • 配置如下,一共是四个参数:stripVersionMode、locationHeaderName、hostValue、protocolsRegex
  • 例如申请是 <font color=”blue”>api.example.com/some/object/name</font>,response 的 location 是 <font color=”blue”>object-service.prod.example.net/v2/some/object/id</font>,最终会被上面的 filter 改写为 <font color=”blue”>api.example.com/some/object/id</font>
spring:
  cloud:
    gateway:
      routes:
      - id: rewritelocationresponseheader_route
        uri: http://example.org
        filters:
        - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, ,
  • stripVersionMode 的策略一共三种:

NEVER_STRIP:不执行
AS_IN_REQUEST:原始申请没有 vesion,就执行
ALWAYS_STRIP:固定执行

  • Location 用于替换 host:port 局部,如果没有就是用 Request 中的 host
  • protocolsRegex 用于匹配协定,如果匹配不上,name 过滤器啥都不做

RewriteResponseHeader

  • RewriteResponseHeader 很好了解:批改响应 header,参数有三个:header 的 key,匹配 value 的正则表达式,批改 value 的后果
  • 上面的配置示意批改响应 header 中 <font color=”blue”>X-Response-Red</font> 这个 key 的 value,找到 password=xxx 的内容,改成 password=*
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
          - Path=/test/**
          filters:
          - RewriteResponseHeader=X-Response-Red, , password=[^&]+, password=***

SecureHeaders

  • SecureHeaders 会在响应的 header 中增加很多和平安相干的内容,配置如下:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
          - Path=/hello/**
          filters:
          - SecureHeaders
  • 响应如下,可见 header 中增加了很多信息:

  • 如果不想返回上图中的某些内容,能够在配置文件中敞开掉,如下图红框,x-frame-options 和 strict-transport-security 两项被设置为不返回了:

  • 再试试,失去如下响应,可见 x -frame-options 和 strict-transport-security 都没有返回:

SetPath

  • SetPath 配合 predicates 应用,上面的配置会将申请 <font color=”blue”>/test/str</font> 改成 <font color=”blue”>/hello/str</font>,可见这个 segment 是在 predicates 中赋值的,而后再 filters 中拿来用:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      filter:
        secure-headers:
          disable:
            - x-frame-options
            - strict-transport-security
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
            - Path=/test/{segment}
          filters:
            - SetPath=/hello/{segment}

SetRequestHeader

  • SetRequestHeader 顾名思义,就是改写申请的 header,将指定 key 改为指定 value,如果该 key 不存在就创立:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      filter:
        secure-headers:
          disable:
            - x-frame-options
            - strict-transport-security
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
            - Path=/hello/**
          filters:
            - SetRequestHeader=X-Request-Red, Blue
  • 和 SetPath 相似,SetRequestHeader 也能够和 predicates 配合,在 predicates 中定义的变量能够用在 SetRequestHeader 中,如下所示,当申请是 /hello/str 的时候,header 中 X -Request-Red 的值就是 <font color=”blue”>Blue-str</font>:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      filter:
        secure-headers:
          disable:
            - x-frame-options
            - strict-transport-security
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
            - Path=/hello/{segment}
          filters:
            - SetRequestHeader=X-Request-Red, Blue-{segment}

SetResponseHeader

  • SetResponseHeader 顾名思义,就是改写响应的 header,将指定 key 改为指定 value,如果该 key 不存在就创立:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      filter:
        secure-headers:
          disable:
            - x-frame-options
            - strict-transport-security
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
            - Path=/hello/**
          filters:
            - SetResponseHeader=X-Request-Red, Blue

SetStatus

  • SetStatus 很好了解:管制返回 code,上面的设置会返回 500:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
            - Path=/hello/**
          filters:
            - SetStatus=500
  • 测试成果如下图,服务提供者的内容会失常返回,然而返回码曾经被改为 500 了:

  • 如果您想用 SetStatus 批改返回码,同时又不想丢掉实在的返回码,能够减少如下配置,这样实在的返回码就被放在名为 <font color=”blue”>original-status-header-name</font> 的 key 中了:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      set-status:
        original-status-header-name: aaabbbccc
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
            - Path=/hello/**
          filters:
            - SetStatus=500

StripPrefix

  • StripPrefix 是个很罕用的 filter,例如申请是 <font color=”blue”>/aaa/bbb/hello/str</font>,咱们要想将其转为 <font color=”blue”>/hello/str</font>,用 <font color=”blue”>StripPrefix=2</font> 即可,后面两级 path 都被删掉了:
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      set-status:
        original-status-header-name: aaabbbccc
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
            - Path=/aaa/**
          filters:
            - StripPrefix=2
  • 如下图,响应失常:

Retry

  • 顾名思义,Retry 就是重试,须要以下参数配合应用:
  1. retries:重试次数
  2. statuses:遇到什么样的返回状态才重试,取值参考:org.springframework.http.HttpStatus
  3. methods:那些类型的办法会才重试(GET、POST 等),取值参考:org.springframework.http.HttpMethod
  4. series:遇到什么样的 series 值才重试,取值参考:org.springframework.http.HttpStatus.Series
  5. exceptions:遇到什么样的异样才重试
  6. backoff:重试策略,由多个参数形成,例如 firstBackoff
  • 参考配置如下:
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

RequestSize

  • RequestSize 也很罕用:管制申请大小,能够应用 <font color=”blue”>KB</font> 或者 <font color=”blue”>MB</font> 等单位,超过这个大小就会返回 413 谬误(Payload Too Large),
spring:
  cloud:
    gateway:
      routes:
      - id: request_size_route
        uri: http://localhost:8080/upload
        predicates:
        - Path=/upload
        filters:
        - name: RequestSize
          args:
            maxSize: 5000000
  • 留神,如果没有设置 RequestSize,Spring Cloud Gateway 默认的下限是 <font color=”red”>5MB</font>

SetRequestHostHeader

  • SetRequestHostHeader 会批改申请 header 中的 host 值
  • 上面的配置,会将申请 header 中的 host 改为 <font color=”blue”>aaabbb</font>
server:
  #服务端口
  port: 8081
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
            - Path=/hello/**
          filters:
        - name: SetRequestHostHeader
        args:
          host: aaabbb
  • 在服务提供者的代码中打断点,如下图,可见 host 曾经被改为 <font color=”blue”>aaabbb</font>

ModifyRequestBody

  • ModifyRequestBody 用于批改申请的 body 内容,这里官网举荐用代码来配置,如下所示,申请 body 中本来是字符串,后果被改成了 Hello 对象的实例:

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

ModifyResponseBody

  • ModifyResponseBody 与后面的 ModifyRequestBody 相似,官网倡议用代码实现,上面的代码作用是将响应 body 的内容改为全副大写:
@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();}

TokenRelay

  • 在应用第三方鉴权的时候,如 OAuth2,用 TokenRelay 能够将第三方的 token 转发到服务提供者那里去:
spring:
  cloud:
    gateway:
      routes:
      - id: resource
        uri: http://localhost:9000
        predicates:
        - Path=/resource
        filters:
        - TokenRelay=
  • 记得还要增加 jar 包依赖 <font color=”blue”>org.springframework.boot:spring-boot-starter-oauth2-client</font>

设置全局 filter

  • 后面的例子中,所有 filter 都放在路由策略中,配合 predicates 一起应用的,如果您想配置全局失效的 filter,能够在配置文件中做以下设置,上面的配置示意 AddResponseHeader 和 PrefixPath 会解决所有申请,和路由设置无关:
spring:
  cloud:
    gateway:
      default-filters:
      - AddResponseHeader=X-Response-Default-Red, Default-Blue
      - PrefixPath=/httpbin
  • 至此,大部分内置过滤器咱们曾经理解了,有几个稍微简单的留待前面的章节深刻学习

你不孤独,欣宸原创一路相伴

  1. Java 系列
  2. Spring 系列
  3. Docker 系列
  4. kubernetes 系列
  5. 数据库 + 中间件系列
  6. DevOps 系列

欢送关注公众号:程序员欣宸

微信搜寻「程序员欣宸」,我是欣宸,期待与您一起畅游 Java 世界 …
https://github.com/zq2599/blog_demos

退出移动版