• Spring Cloud Gateway 参考指南


    👏大家好,欢迎来到👏阿提说说👏博客
    🌞“纸上得来终觉浅,绝知此事要躬行。”(南宋)陆游

    🌲目前相关的教程虽然有很多,但总觉得被各位大佬压缩,看到的只是一部分知识,并不全面,因此作者根据Spring Cloud Gateway 官方参考指南写下了这篇中文版文字教程,并且录制了一些视频教程,希望更有助于您理解。

    🍀Spring Cloud Gateway 版本为 3.1.3

    该项目提供了一个基于Spring生态的API网关。Spring Cloud Gateway。Spring Cloud Gateway旨在提供一个种简单有效的方式去路由API,并给API提供相应关注点:如:security、monitoring/metrics和resiliency。

    1. 如何引入Spring Cloud Gateway

    要在项目中引入Spring Cloud Gateway,您可以这样做:

    1. 引入Spring Cloud 统一版本依赖管理,通过引入该配置,无需指定Spring Cloud相关组件版本
    <dependencyManagement>
    	<dependencies>
    		<dependency>
    			<groupId>org.springframework.cloudgroupId>
    			<artifactId>spring-cloud-dependenciesartifactId>
    			<version>${spring-cloud.version}version>
    			<type>pomtype>
    			<scope>importscope>
    		dependency>
    	dependencies>
    dependencyManagement>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. 引入Spring Cloud Gateway配置
    <dependency>
    	<groupId>org.springframework.cloudgroupId>
    	<artifactId>spring-cloud-starter-gatewayartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4

    🚩 如果引入了Spring Cloud Gateway,又不想开启,可以设置spring.cloud.gateway.enabled=false

    ❗️ Spring Cloud Gateway建立在Spring Boot 2.xSpring WebFluxProject Reactor之上,当您使用Spring Cloud Gateway时,以前的同步库(Spring Data 、Spring Security等)并不适用。如果您不熟悉这些项目,建议您在使用Spring Cloud Gateway之前,先阅读他们的文档,熟悉一些概念。

    ❗️ Spring Cloud Gateway 使用Spring Boot 和Spring Webflux 提供的Netty环境运行,因此在传统的Servlet容器中不会生效。

    2. 相关术语

    • Route: 路由,网关基础模块。它由ID、目标URI、断言集合和过滤器集合组成。如果断言为真,则匹配到该路由。
    • Predicate:这是一个Java8 的函数断言。输入类型是Spring Framework 的 ServerWebExchange
    • Filter: 使用指定工厂构建的GatewayFilter的实例。在这里,您能够修改request请求和response返回在发送到下游服务之前或者之后。

    3. 如何工作

    下图是SPring Cloud Gateway的工作示意图:
    在这里插入图片描述
    客户端向Spring Cloud Gateway请求。如果网关处理程序(Gateway Handler Mapping)确定请求与路由匹配,那么将其发送到网关的Web处理器(Gateway Web Handler)。该处理程序通过过滤器链来处理请求。过滤器链被虚线分割的原因是,过滤器可以在请求发送前后运行逻辑,先执行所有的“pre”过滤器逻辑,后执行“post”过滤器逻辑。

    ✅ 在未定义端口的URI中,HTTP默认为80,HTTPS默认为443。

    4. 配置路由断言工厂和网关过滤工厂

    有两种方法配置谓词和过滤器:简写和完全展开方式。下面的例子大都用的简写。

    4.1 简写

    简写配置由过滤器名称,后跟等号,后跟逗号分割的参数值。

    application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: after_route
            uri: https://example.org
            predicates:
            - Cookie=mycookie,mycookievalue
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4.2 完全展开

    完全展开方式具有标准的name/value 对。一般带有name 和 args 两个key。args用来配置断言或过滤器的键值对映射。

    application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: after_route
            uri: https://example.org
            predicates:
            - name: Cookie
              args:
                name: mycookie
                regexp: mycookievalue
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    5. 路由断言工厂

    Spring Cloud Gateway 路由匹配作为Spring WebFlux HandlerMapping 基础设施的一部分。Spring Cloud Gateway内置了很多路由断言工厂。用于匹配HTTP请求的不同属性。

    5.1 After Route Predicate Factory

    接收一个java ZonedDateTime的时间参数,表示这个时间之后的请求才能正确匹配路由。

    Example 1.application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: after_route
            uri: https://example.org
            predicates:
            - After=2017-01-20T17:42:47.789-07:00[America/Denver]
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这个路由匹配 Jan 20, 2017 17:42 Mountain Time (Denver)之后的请求。

    5.2 Before Route Predicate Factory

    接收一个Java ZonedDateTime类的时间参数,表示这个时间之前的请求才能正确匹配路由。

    Example 2. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: before_route
            uri: https://example.org
            predicates:
            - Before=2017-01-20T17:42:47.789-07:00[America/Denver]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5.3 Between Route Predicate Factory

    接收两个Java ZonedDateTime类的时间参数,表示在第一个时间之后,第二个时间之前的请求才能正确匹配路由。

    Example 3. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: between_route
            uri: https://example.org
            predicates:
            - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5.4 Cookie Route Predicate Factory

    接收两个参数,分别为name 和 regexp(Java正则表达式),表示cookie中携带的name值满足正则表达式regexp,则被路由。

    Example 4. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: cookie_route
            uri: https://example.org
            predicates:
            - Cookie=chocolate, ch.p
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5.5 Header Route Predicate Factory

    接收两个参数,header 和 regexp(Java正则表达式),表示header中携带的name值满足正则表达式regexp,则被路由

    Example 5. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: header_route
            uri: https://example.org
            predicates:
            - Header=X-Request-Id, \d+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5.6 Host Route Predicate Factory

    接收一个主机名称的集合参数,用逗号分割,表示该断言与主机头匹配则被路由。

    Example 6. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: host_route
            uri: https://example.org
            predicates:
            - Host=**.somehost.org,**.anotherhost.org
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    支持URI模板变量(如{sub}.myhost.org)。
    当Host 头的值为www.somehost.org 或 beta.somehost.org 或 www.anotherhost.org都能匹配该路由。

    Predicate 会提取URI模板变量作为map集合,并放置在ServerWebExchange.getAttributes()中,key定义为ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE,这些值能在GatewayFilter 工厂中使用。

    5.7 Mehtod Route Predicate Factory

    接收一个或多个http请求参数,如果请求方法匹配,则被路由。

    Example 7. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: method_route
            uri: https://example.org
            predicates:
            - Method=GET,POST
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5.8 Path Route Predicate Factory

    接收两个参数,分别是Spring PathMatcher patterns 列表 和 一个matchTrailingSlash的可选标志(默认为true)。

    Example 8. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: path_route
            uri: https://example.org
            predicates:
            - Path=/red/{segment},/blue/{segment}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    如果请求地址是 /red/1 或 /red/1/ 或 /red/blue 或 /blue/green,那么路由将会被匹配。

    如果matchTrailingSlash 设置为false,那么/red/1/不会被匹配。

    Predicate 会提取URI模板变量作为map集合,并放置在ServerWebExchange.getAttributes()中,key定义为ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE,这些值能在GatewayFilter 工厂中使用。

    可以使用一个实用方法(调用get)来简化对这些变量的访问。下面的例子展示了如何使用get方法:

    Map, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);
    
    String segment = uriVariables.get("segment");
    
    • 1
    • 2
    • 3

    5.9 Query Route Predicate Factory

    接收两个参数,分别是一个必须的param和一个可选的regexp。

    Example 9. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: query_route
            uri: https://example.org
            predicates:
            - Query=green
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: query_route
            uri: https://example.org
            predicates:
            - Query=red, gree.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    如果请求中包含一个red查询参数,且该参数的值匹配gree.正则表达式,则上述路由匹配。所以green和greet是匹配的。

    5.10 RemoteAddr Route Predicate Factory

    接收一个sources列表(最小1个),CIDR表示法(IPv4或IPv6)字符串,例如192.168.0.1/16(其中192.168.0.1是一个IP地址,16是一个子网掩码)。

    Example 10. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: remoteaddr_route
            uri: https://example.org
            predicates:
            - RemoteAddr=192.168.1.1/24
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    如果请求的远程地址是192.168.1.10,则此路由被匹配。

    5.10.1 修改远程地址的解析方式

    默认情况下,RemoteAddr 路由谓词工厂使用来自传入请求的远程地址。如果 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 前运行的受信任基础设施数量相关的索引。例如,如果 Spring Cloud Gateway 只能通过 HAProxy 访问,则应使用值 1。如果在访问 Spring Cloud Gateway 之前需要两跳可信基础架构,则应使用值 2。
      考虑以下标头值:

    X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3

    以下 maxTrustedIndex 值产生以下远程地址:

    maxTrustedIndexresult
    [Integer.MIN_VALUE,0](invalid, IllegalArgumentException during initialization)
    10.0.0.3
    20.0.0.2
    30.0.0.1
    [4, Integer.MAX_VALUE]0.0.0.1

    以下示例显示了如何使用 Java 实现相同的配置:

    Example 11. GatewayConfig.java

    RemoteAddressResolver resolver = XForwardedRemoteAddressResolver
        .maxTrustedIndex(1);
    
    ...
    
    .route("direct-route",
        r -> r.remoteAddr("10.1.1.1", "10.10.1.1/24")
            .uri("https://downstream1")
    .route("proxied-route",
        r -> r.remoteAddr(resolver, "10.10.1.1", "10.10.1.1/24")
            .uri("https://downstream2")
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    5.11 Weight Route Predicate Factory

    接收两个参数:分别是group 和 weight(int类型)。权重是按组计算的。

    Example 12. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: weight_high
            uri: https://weighthigh.org
            predicates:
            - Weight=group1, 8
          - id: weight_low
            uri: https://weightlow.org
            predicates:
            - Weight=group1, 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    将有80%的流量被路由到weighthigh.org,20%的流量被路由到weightlow.org

    5.12 XForwarded Remote Addr Route Predicate Factory

    接收一个sources列表(最小大小为 1),这些源是 CIDR 表示法(IPv4 或 IPv6)字符串,例如 192.168.0.1/16(其中 192.168.0.1 是 IP 地址,16 是子网掩码)

    此路由断言允许基于 X-Forwarded-For HTTP 标头过滤请求。

    这可以与反向代理一起使用,例如负载平衡器或 Web 应用程序防火墙,其中仅当请求来自这些反向代理使用的受信任的 IP 地址列表时才允许请求。

    以下示例配置 XForwardedRemoteAddr 路由谓词:

    Example 13. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: xforwarded_remoteaddr_route
            uri: https://example.org
            predicates:
            - XForwardedRemoteAddr=192.168.1.1/24
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    如果 X-Forwarded-For 标头包含例如 192.168.1.10,则此路由匹配。

    6. 网关过滤器工厂(GatewayFilter)

    路由过滤器允许修改传入的HTTP请求和传出的HTTP响应。Spring Cloud Gateway包括了许多内置的GatewayFilter Factories。

    关于过滤器的更多示例,查看单元测试

    6.1 AddRequestHeader GatewayFilter Factory

    接收一个namevalue参数,并将信息添加到下游的请求头中。

    Example 14. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: add_request_header_route
            uri: https://example.org
            filters:
            - AddRequestHeader=X-Request-red, blue
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    AddRequestHeader支持使用URI变量来匹配path 或 host。

    Example 15. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: add_request_header_route
            uri: https://example.org
            predicates:
            - Path=/red/{segment}
            filters:
            - AddRequestHeader=X-Request-Red, Blue-{segment}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    6.2 AddRequestParameter GatewayFilter Factory

    接收一个name 和 value 参数,并添加信息到下游的请求中。

    Example 16. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: add_request_parameter_route
            uri: https://example.org
            filters:
            - AddRequestParameter=red, blue
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    支持使用URI变量来匹配path 或 host。

    Example 17. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: add_request_parameter_route
            uri: https://example.org
            predicates:
            - Host: {segment}.myhost.org
            filters:
            - AddRequestParameter=foo, bar-{segment}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    6.3 AddResponseHeader GatewayFilter Factory

    接收一个name 和 value 参数,并将信息添加到下游匹配请求的响应头中。

    Example 18. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: add_response_header_route
            uri: https://example.org
            filters:
            - AddResponseHeader=X-Response-Red, Blue
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    支持使用URI变量来匹配path 或 host。

    Example 19. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: add_response_header_route
            uri: https://example.org
            predicates:
            - Host: {segment}.myhost.org
            filters:
            - AddResponseHeader=foo, bar-{segment}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    6.4 DedupeResponseHeader GatewayFilter Factory

    接收一个name参数和一个可选的strategy参数,name 参数根据空格分割。

    Example 20. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: dedupe_response_header_route
            uri: https://example.org
            filters:
            - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    当网关CROS和下游响应头都有Access-Control-Allow-Credentials 和 Access-Control-Allow-Origin时,将删除重复的响应头。

    DedupeResponseHeader过滤器也接收可选的strategy参数,可接收的值是RETAIN_FIRST (default), RETAIN_LAST 和 RETAIN_UNIQUE

    6.5 CircuitBreaker GatewayFilter Factory(演示)

    使用 Spring Cloud CircuitBreaker的API将网关路由包装到断路器中。Spring Cloud CircuitBreaker 支持多种库用于Spring Cloud Gateway。比如Resilience4J。

    要启用Spring Cloud CircuitBreaker过滤器,你需要引入spring-cloud-starter-circuitbreaker-reactor-resilience4j,如下是配置示例:

    Example 21. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: circuitbreaker_route
            uri: https://example.org
            filters:
            - CircuitBreaker=myCircuitBreaker
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    要配置 circuit breaker,可以详细查看Resilience4J Documentation

    Spring Cloud CircuitBreaker 过滤器也支持接收可选的fallbackUri参数。当前,仅forward:支持,如果请求失败,请求将会跳转到匹配URI的controller中。

    Example 22. application.yml

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    🚩 RewritePath 表示将/consumingServiceEndpoint路径在请求前重写为/backingServiceEndpoint

    下面是Java的实现方式:

    Example 23. Application.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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    当前请求被熔断时,将被回调到/inCaseofFailureUseThis

    ✅ 动图演示

    gateway: 测试网关
    backing-service: 测试后端服务

    • 熔断跳转到inCaseOfFailureUseThis
      在这里插入图片描述

    • 重写跳转到backingServiceEndpoint
      在这里插入图片描述

    这里fallbackUri主要使用在网关应用程序内部定义controller或者handler。您也可以重路由到外部应用程序。如下示例:

    Example 24. application.yml

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    该示例中,网关没有fallback 端点或处理程序。但是注册了一个localhost:9994的应用程序。

    在请求被转发到fallback的时候,Spring Cloud CircuitBreaker Gateway filter 也提供Throwable异常。它被添加到ServerWebExchange ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR中,以便可以在网关应用程序中使用。

    对于外部controller/handler场景,可以添加带有异常详情信息的头。您可以在FallbackHeaders GatewayFilter Factory section中找到更多详情。

    6.5.1 根据状态码熔断

    通过配置的statusCodes,当返回配置的状态码时,请求熔断。状态码可以配置整型状态码值或者HttpStatus的枚举字符串。

    Example 25. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: circuitbreaker_route
            uri: lb://backing-service:8088
            predicates:
            - Path=/consumingServiceEndpoint
            filters:
            - name: CircuitBreaker
              args:
                name: myCircuitBreaker
                fallbackUri: forward:/inCaseOfFailureUseThis
                statusCodes:
                  - 500
                  - "NOT_FOUND"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    Java 代码表示

    Example 26. Application.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").addStatusCode("INTERNAL_SERVER_ERROR"))
                    .rewritePath("/consumingServiceEndpoint", "/backingServiceEndpoint")).uri("lb://backing-service:8088")
            .build();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    6.6 FallbackHeaders GatewayFilter Factory

    FallbackHeaders 工厂允许您在转发到外部应用程序的fallbackUri中添加Spring Cloud CircuitBreaker 详细的异常信息,如下所示:

    Example 27. application.yml

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在该例中,在运行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”)

    更多详情查看Spring Cloud CircuitBreaker Factory section

    6.7 MapRequestHeader GatewayFilter Factory(演示)

    接收两个参数,分别是fromHeader 和 toHeader。它会创建一个新的header(toHeader),并从fromHeader中提取值。如果输入的header不存在,该过滤器不会执行。如果新的header已经存在,那么它将被追加新值。如下所示:

    Example 28. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: map_request_header_route
            uri: https://example.org
            filters:
            - MapRequestHeader=Blue, X-Request-Red
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    该示例会将X-Request-Red:头添加到下游请求中,值为传入的HTTP请求Blue值。

    ✅视频演示

    MapperRequestHeader GatewayFilter示例演示

    6.8 PrefixPath GatewayFilter Factory

    接收一个参数prefix

    Example 29. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: prefixpath_route
            uri: https://example.org
            filters:
            - PrefixPath=/mypath
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    该示例将在所有匹配请求路径前加上前缀/mypath,因此请求/hello时,将发送到/mypath/hello中。

    6.9 PreserveHostHeader GatewayFilter Factory(演示)

    该过滤工厂没有接收参数。设置了该Filter后,GatewayFilter将不使用由HTTP客户端确定的host header ,而是发送原始host header。

    Example 30. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: preserve_host_route
            uri: https://example.org
            filters:
            - PreserveHostHeader
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ✅视频演示

    PreserveHostHeader GatewayFilter 示例演示

    6.10 RequestRateLimiter GatewayFilter Factory

    该过滤器使用RateLimiter来实现是否允许继续执行该请求。如果不允许继续执行,返回HTTP 429 - Too Many Requests(默认情况下)。

    该过滤器可以配置一个可选的keyResolver 参数和rate limiter参数。

    keyResolverKeyResolver的一个实现类,在配置中,按名称使用SpEL引用bean。#{@myKeyResolver}是引用名为’myKeyResolver’的bean的SpEL表达式。

    Example 31. KeyResolver.java

    public interface KeyResolver {
        Mono<String> resolve(ServerWebExchange exchange);
    }
    
    • 1
    • 2
    • 3

    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}
    
    • 1
    • 2

    6.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。

    通过在replenishRateburstCapacity中设置相同的值来实现稳定的速率。可通过设置burstCapacity高于replenishRate来允许临时突发流量。在这种情况下,限流器需要在两次突发之间留出一段时间(根据replenishRate),因为连续两次突发将导致请求丢失 (HTTP 429 - Too Many Requests)。如下列表配置了一个redis-rate-limiter:

    比如:replenishRate=1requestedTokens=60burstCapacity=60将限制为 1 request/min

    Example 33. application.yml

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    配置一个KeyResolver

    **Example 34. Config.java

    @Bean
    KeyResolver userKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
    }
    
    • 1
    • 2
    • 3
    • 4

    这定义了每个用户10个请求的限制。允许20个突发,但下一秒只有10个请求可用。KeyResolver是一个简单的获取user请求参数的工具(注意:不建议用于生产)。

    限流器也可以定义为RateLimiter接口的实现 bean。在配置中,按名称使用SpEL引用bean。#{@myRateLimiter}是引用名为myRateLimiter的bean的SpEL表达式。

    Example 35. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: requestratelimiter_route
            uri: https://example.org
            filters:
            - name: RequestRateLimiter
              args:
                rate-limiter: "#{@myRateLimiter}"
                key-resolver: "#{@userKeyResolver}"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    ✅视频演示

    RetryGatewayFilter 示例教程演示

    6.11 RedirectTo GatewayFilter Factory

    接收两个参数:statusurl
    status是300类重定向HTTP码,如301。该url应该是一个有效的URL,值是Location header的值。
    对于相对路径,应该使用uri: no://op作为路由定义。

    Example 36. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: prefixpath_route
            uri: https://example.org
            filters:
            - RedirectTo=302, https://acme.org
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    该例将发送一个302重定向状态码到Location:https://acme.org

    6.12 RemoveRequestHeader GatewayFilter Factory

    接收一个name参数,该值是将要被删除header的name。

    Example 37. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: removerequestheader_route
            uri: https://example.org
            filters:
            - RemoveRequestHeader=X-Request-Foo
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    该例表示将从header中删除X-Request-Foo

    6.13 RemoveResponseHeader GatewayFilter Factory

    接收一个参数name,name将在响应返回之前被删除。

    Example 38. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: removeresponseheader_route
            uri: https://example.org
            filters:
            - RemoveResponseHeader=X-Response-Foo
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    该例表示响应在返回网关之前将从header中删除X-Response-Foo

    可以使用spring.cloud.gateway.default-filters配置默认过滤,该默认过滤对所有路由有效。

    6.14 RemoveRequestParameter GatewayFilter Factory

    接收一个name参数,它是要被删除请求参数的name值。

    Example 39. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: removerequestparameter_route
            uri: https://example.org
            filters:
            - RemoveRequestParameter=red
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    该例表示在将请求发送到下游之前,删除red参数。

    6.15 RequestHeaderSize GatewayFilter Factory

    接收两个参数,maxSizeerrorHeaderName
    maxSize表示请求头的最大数据带下(包括key和value)。errorHeaderName用于设置响应头的名称,包含错误信息,默认名称为errorMessage

    Example 40. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: requestheadersize_route
            uri: https://example.org
            filters:
            - RequestHeaderSize=1000B
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    该示例表示如果请求超过了1000Bytes,将发送一个431的状态码。

    6.16 RewritePath GatewayFilter Factory

    接收一个regexpreplacement参数。使用了Java正则表达式来重写请求地址。

    Example 41. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: rewritepath_route
            uri: https://example.org
            predicates:
            - Path=/red/**
            filters:
            - RewritePath=/red/?(?>.*), /$\{segment}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    对于/red/blue请求路径,将在发送到下游之前替换为/blue。因为YAML规范,要把$替换为$\

    6.17 RewriteLocationResponseHeader GatewayFilter Factory

    该过滤器修改Location响应头的值,经常用于去掉一些敏感信息。接收参数分别是:
    stripVersionMode, locationHeaderName, hostValue, protocolsRegex

    Example 42. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: rewritelocationresponseheader_route
            uri: http://example.org
            filters:
            - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, ,
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    示例表示,一个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。

    6.18 RewriteResponseHeader GatewayFilter Factory

    接收nameregexpreplacement三个参数。使用Java正则表达式重写响应header头。

    Example 43. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: rewriteresponseheader_route
            uri: https://example.org
            filters:
            - RewriteResponseHeader=X-Response-Red, , password=[^&]+, password=***
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在下游响应返回到网关后,该示例将把/42?user=ford&password=omg!what&flag=true头的值,设置为/42?user=ford&password=***&flag=true。您必须使用$\代替$

    6.19 SaveSession GatewayFilter Factory

    SaveSession GatewayFilter Factory将调用转发到下游之前强制执行WebSession::save 操作。这在使用 Spring Session 之类时特别有用,需要确保会话状态在进行转发调用之前已保存。

    Example 44. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: save_session
            uri: https://example.org
            predicates:
            - Path=/foo/**
            filters:
            - SaveSession
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    如果你希望要将Spring Security与Spring Session集成,并要确保安全信息都传到下游,这样做将是很重要的。

    6.20 SecureHeaders GatewayFilter Factory

    根据这篇blog的建议,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-download-options

    • x-permitted-cross-domain-policies

    使用spring.cloud.gateway.filter.secure-headers.disable禁用默认值,全小写逗号分割

    6.21 SetPath GatewayFilter Factory

    SetPath GatewayFilter Factory 采用一个template 路径参数。它提供了一种简单的方法,通过允许路径的模板化segments来操作请求路径。使用Spring Framework中的URI模板,允许多个匹配segments。

    Example 45. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: setpath_route
            uri: https://example.org
            predicates:
            - Path=/red/{segment}
            filters:
            - SetPath=/{segment}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    如上所示:请求/red/blue,将在请求下游时将路径设置为/blue

    6.22 SetRequestHeader GatewayFilter Factory

    采用namevalue参数。

    Example 46. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: setrequestheader_route
            uri: https://example.org
            filters:
            - SetRequestHeader=X-Request-Red, Blue
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    该GatewayFilter将会使用给定的name替换所有的header,而不是添加。因此会将请求头从X-Request-Red:1234设置为X-Request-Red:Blue

    SetRequestHeader 允许使用path或者host的URI变量。

    Example 47. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: setrequestheader_route
            uri: https://example.org
            predicates:
            - Host: {segment}.myhost.org
            filters:
            - SetRequestHeader=foo, bar-{segment}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    6.23 SetResponseHeader GatewayFilter Factory

    两个参数namevalue

    Example 48. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: setresponseheader_route
            uri: https://example.org
            filters:
            - SetResponseHeader=X-Response-Red, Blue
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    该GatewayFilter将会使用给定的name替换所有的header,而不是添加。下游响应的头X-Response-Red:1234将会替换成X-Response-Red:Blue

    SetResponseHeader 也使用path或者host的URI变量。

    Example 49. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: setresponseheader_route
            uri: https://example.org
            predicates:
            - Host: {segment}.myhost.org
            filters:
            - SetResponseHeader=foo, bar-{segment}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    6.24 SetStatus GatewayFilter Factory(演示)

    接收一个参数status,必须是一个可用的Spring HttpStatus值,可用是整数或者枚举字符串。

    Example 50. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: setstatusstring_route
            uri: https://example.org
            filters:
            - SetStatus=UNAUTHORIZED
          - id: setstatusint_route
            uri: https://example.org
            filters:
            - SetStatus=401
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    该示例,将HTTP status响应头设置为401。

    使用SetStatus 可以在响应中返回代理请求中的原始Http 状态码。如下配置,将header添加到响应中。

    Example 51. application.yml

    spring:
      cloud:
        gateway:
          set-status:
            original-status-header-name: original-http-status
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ✅演示

    如下示例配置了original-status-header-name: original-http-statusSetStatus=401,效果如下:

    在这里插入图片描述

    6.25 StripPrefix GatewayFilter Factory

    接收一个parts参数。 parts参数指示在将请求发送到下游之前,要从请求中去除的路径中的节数。

    Example 52. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: nameRoot
            uri: https://nameservice
            predicates:
            - Path=/name/**
            filters:
            - StripPrefix=2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    该示例表示当网关发送/name/blue/red请求时,实际向下游请求的地址是nameservice/red

    6.26 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

    Example 53. application.yml

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    ❗️ 当重试过滤器与任何带body的HTTP请求使用时,body会被缓存。body被缓存在请求定义的的ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR中,对象类型是:org.springframework.core.io.buffer.DataBuffer

    使用单个statusmethod,可以使用简便的方式添加:
    Example 54. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: retry_route
            uri: https://example.org
            filters:
            - name: Retry
              args:
                retries: 3
                statuses: INTERNAL_SERVER_ERROR
                methods: GET
                backoff:
                  firstBackoff: 10ms
                  maxBackoff: 50ms
                  factor: 2
                  basedOnPreviousValue: false
    
          - id: retryshortcut_route
            uri: https://example.org
            filters:
            - Retry=3,INTERNAL_SERVER_ERROR,GET,10ms,50ms,2,false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    ✅演示

    RetryGatewayFilter 示例教程演示

    6.27 RequestSize GatewayFilter Factory

    当请求大小大于允许的限制时,RequestSize GatewayFilter Factory可以限制请求不到达下游服务。过滤器以RequestSize作为参数,这是定义请求的允许大小限制(以字节为单位)。

    Example 55. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: request_size_route
            uri: http://localhost:8080/upload
            predicates:
            - Path=/upload
            filters:
            - name: RequestSize
              args:
                maxSize: 5000000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    当请求因大小而被拒绝时, 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
    
    • 1

    ❗️ 如果未在路由定义中作为filter参数提供,则默认请求大小将设置为5 MB

    6.28 SetRequestHostHeader GatewayFilter Factory

    接收一个host参数,用于覆盖主机头。

    Example 56. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: set_request_host_header_route
            uri: http://localhost:8080/headers
            predicates:
            - Path=/headers
            filters:
            - name: SetRequestHostHeader
              args:
                host: example.org
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    该示例表示使用example.org代替host头的值。

    6.29 ModifyRequestBodyGatewayFilterFactory

    此过滤器可用于在请求主体被网关发送到下游之前对其进行修改。

    ❗️ 只能使用Java DSL配置此过滤器。如果没有body,RewriteFilter 会传递null。

    @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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    6.30 Modify Response Body GatewayFilter Factory

    此过滤器可用于在将响应正文发送回客户端之前对其进行修改。

    ❗️ 只能使用Java DSL配置此过滤器。如果没有body,RewriteFilter 会传递null。

    
    @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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    6.31 Token Relay GatewayFilter Factory

    令牌中继是OAuth2使用者充当客户端并将传入令牌转发给传出资源请求的地方。使用者可以是纯客户端(如SSO应用程序)或资源服务器。

    Spring Cloud Gateway 可以将OAuth2访问令牌转发到其代理的服务下游。要将此功能添加到网关,您需要添加TokenRelayGatewayFilterFactory

    App.java

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("resource", r -> r.path("/resource")
                        .filters(f -> f.tokenRelay())
                        .uri("http://localhost:9000"))
                .build();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    或者

    application.yaml

    spring:
      cloud:
        gateway:
          routes:
          - id: resource
            uri: http://localhost:9000
            predicates:
            - Path=/resource
            filters:
            - TokenRelay=
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    它将(除了让登录和获取令牌之外)将身份验证令牌传递给下游的服务(在本例中是/resource)。

    开启该功能要添加依赖到Spring Cloud Gateway

    • org.springframework.boot:spring-boot-starter-oauth2-client

    工作原理:TokenRelayGatewayFilterFactory会从认证的用户中提取access token,并放入发送给下游的请求中。示例见:thi project.

    ❗️ ReactiveOAuth2AuthorizedClientService的默认实现是TokenRelayGatewayFilterFactory,使用内存存储,如果需要自定义,需要自己实现ReactiveOAuth2AuthorizedClientService 。

    6.32 CacheRequestBody GatewayFilter Factory

    由于请求body流只能读取一次,因此我们需要缓存请求的body。可以使用CacheRequestBody 缓存body,并从exchange 中获取该body。

    @Bean
    public RouteLocator routes(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("cache_request_body_route", r -> r.path("/downstream/**")
                .filters(f -> f.prefixPath("/httpbin")
                    .cacheRequestBody(String.class).uri(uri))
            .build();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Example 57. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: cache_request_body_route
            uri: lb://downstream
            predicates:
            - Path=/downstream/**
            filters:
            - name: CacheRequestBody
              args:
                bodyClass: java.lang.String
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    CacheRequestBody 将提取请求body并转换成body 指定的类。(本例中是java.lang.String)。缓存中定义的key为ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR

    ❗️ 仅支持http/https 请求

    6.33 Default Filters

    可以使用spring.cloud.gateway.default-filters作为所有路由的过滤器。该配置接收一个filter列表,如下:

    Example 58. application.yml

    spring:
      cloud:
        gateway:
          default-filters:
          - AddResponseHeader=X-Response-Default-Red, Default-Blue
          - PrefixPath=/httpbin
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    7. Global Filters

    GlobalFilter接口与GatewayFilter具有相同的签名。是有条件地应用于所有路由的特殊过滤器。

    ❗️ 此接口和用法可能在将来的里程碑版本中发生更改

    7.1 全局Filter和GatewayFilter组合排序

    当请求匹配到路由时,web 过滤处理器会将所有的 GlobalFilter 实例和指定的GatewayFilter实例添加到过滤器链。filter的排序由org.springframework.core.Ordered接口决定,可以通过getOrder()方法或者@Order注释来设置。

    由于Spring Cloud Gateway将用于执行过滤器逻辑区分为“前置”和“后置”阶段,具有最高优先级的过滤器将是“前置”阶段的第一个,而“后置”阶段的最后一个。

    如下配置了一个过滤器链:

    Example 59. ExampleConfiguration.java

    @Bean
    public GlobalFilter customFilter() {
        return new CustomGlobalFilter();
    }
    
    public class CustomGlobalFilter implements GlobalFilter, Ordered {
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            log.info("custom global filter");
            return chain.filter(exchange);
        }
    
        @Override
        public int getOrder() {
            return -1;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    7.2 Forward Routing Filter

    ForwardRoutingFilter在exchange属性ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR中查找URI。如果URL有一个forward scheme (如 forward:///localendpoint),它将使用Spring DispatcherHandler 来处理请求。请求URL的路径部分将被转发URL中的路径覆盖。未修改的原始URL将附加到 ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR属性中的列表中。

    7.3 ReactiveLoadBalancerClientFilter

    ReactiveLoadBalancerClientFilter在exchange属性ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR中查找URI。如果URL有一个lb scheme (如 lb://myservice),它将使用Spring Cloud ReactorLoadBalancer 将名称(在前一个示例中为myservice)解析为实际主机和端口,并替换URI。未修改的原始URL将附加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR属性中的列表中。过滤器还将查看ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR属性,查看它是否等于lb,然后应用相同的规则。

    Example 60. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: myRoute
            uri: lb://service
            predicates:
            - Path=/service/**
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ❗️默认情况下,如果一个服务实例在ReactorLoadBalancer中没有发现,则返回503。可以通过设置spring.cloud.gateway.loadbalancer.use404=true来让网关返回404.

    ❗️从ReactiveLoadBalancerClientFilter 返回的ServiceInstance的isSecure 值将覆盖在对网关发出的请求中指定的scheme。例如,如果请求通过HTTPS进入网关,但ServiceInstance表示它不安全,则下游请求将通过HTTP协议。相反的情况也适用。但是,如果在网关配置中为路由指定了GATEWAY_SCHEME_PREFIX_ATTR,则前缀将被删除,并且路由URL生成的scheme将覆盖ServiceInstance配置。

    💡 Gateway支持所有LoadBalancer 能力。详情查看Spring Cloud Commons documentation.

    7.4 Netty Routing Filter

    如果位于 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR属性中的URL具有http 或https 模式,则会运行Netty Routing Filter。它使用Netty HttpClient 发出下游代理请求。响应放在 ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR exchange属性中,以便在以后的过滤器中使用。(有一个处于实验阶段的WebClientHttpRoutingFilter,不需要使用Netty)。

    7.5 Netty Write Response Filter

    如果ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR exchange属性中存在 Netty HttpClientResponse,则运行 NettyWriteResponseFilter 。它在其他所有过滤器完成后运行,并将代理响应写回到网关客户端的响应中。(一个处于实验阶段的,不需要Netty的过滤器WebClientWriteResponseFilter

    7.6 RouteToRequestUrl Filter

    如果ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR exchange属性中存在Route对象,RouteToRequestUrlFilter将运行。它基于请求URI创建一个新的URI,使用Route对象的uri属性进行更新。新的URI被放置在ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR exchange属性中。如果该URI有一个前缀scheme,例如lb:ws://serviceid,则会从该URI中剥离该 lb scheme,并将其放置在ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR中,以便稍后在过滤器链中使用。

    7.7 Websocket Routing Filter

    如果ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR exchange属性中有 wswss scheme,则Websocket Routing Filter将被运行。它使用Spring Web Socket基础模块将Websocket转发到下游。

    URI前缀为lb的Websockets可以被负载均衡,如 lb:ws://serviceid

    ❗️ 如果使用 SockJS 作为普通HTTP的fallback,则应配置普通HTTP路由以及WebSocket路由。

    Example 61. application.yml

    spring:
      cloud:
        gateway:
          routes:
          # SockJS route
          - id: websocket_sockjs_route
            uri: http://localhost:3001
            predicates:
            - Path=/websocket/info/**
          # Normal Websocket route
          - id: websocket_route
            uri: ws://localhost:3001
            predicates:
            - Path=/websocket/**
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    7.8 Gateway Metrics Filter

    要启用网关指标,请将spring-boot-starter-actuator添加为项目依赖项。然后,默认情况下,只要属性spring.cloud.gateway.metrics.enabled未设置为false,网关指标过滤器就会运行。此过滤器添加名为spring.cloud.gateway.requests的计时器指标,并带有以下标记:

    • routeId: route ID.

    • routeUri: API 将被转发的URI

    • outcome: 结果分类,依据 HttpStatus.Series

    • status: 返回client的请求的Http Status

    • httpStatusCode: 返回client的请求的httpStatusCode

    • httpMethod: 用于请求的HTTP方法

    另外通过spring.cloud.gateway.metrics.tags.path.enabled(默认为false)来激活额外的指标:

    • path:请求的路径

    这些指标可以从/actuator/metrics/spring.cloud.gateway.requests获取,并且能够很容易的与Prometheus 集成创建Grafana dashboard

    ❗️ 要将pometheus启用,需要添加micrometer-registry-prometheus为项目依赖。

    7.9 Marking An Exchange As Routed

    网关路由ServerWebExchange之后,它将通过向Exchange属性添加gatewayAlreadyRouted,将该exchange标记为“routed”。一旦一个请求被标记为routed,其他路由过滤器将不会再次路由该请求,将跳过该过滤器。有一些方便的方法可以用来将exchange标记为routed,或者检查exchange是否已经routed。

    • ServerWebExchangeUtils.isAlreadyRouted 有一个ServerWebExchange 对象用来检查是否已routed。
    • ServerWebExchangeUtils.setAlreadyRouted 有一个ServerWebExchange 对象来标记是否routed。

    8. HttpHeadersFilters

    HttpHeadersFilters使用在请求被发送到下游之前,比如在NettyRoutingFilter中使用到了。

    8.1 Forwarded Headers Filter

    Forwarded Headers Filter创建一个Forwarded 头到发送给下游的请求中。它使用当前请求的Host 头,scheme 和端口添加到任何现有的Forwarded 头中。

    8.2 RemoveHopByHop Headers Filter

    RemoveHopByHop 用来在请求中删除头信息。删除的默认标头列表来自IETF

    默认删除的头信息:

    • Connection

    • Keep-Alive

    • Proxy-Authenticate

    • Proxy-Authorization

    • TE

    • Trailer

    • Transfer-Encoding

    • Upgrade

    要更改此设置,通过 spring.cloud.gateway.filter.remove-hop-by-hop.headers配置要删除的头信息。

    8.3 XForwarded Headers Filter

    XForwarded Headers Filter 创建各种X-Forwarded-*头以发送到下游服务。它使用当前请求的Host 头、scheme、port和path来创建各种头信息。

    可以通过布尔属性(默认true)来配置单个的header:

    • 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

    9. TLS and SSL

    网关可以通过常规的 Spring server configuration 来侦听HTTPS上的请求。

    Example 62. application.yml

    server:
      ssl:
        enabled: true
        key-alias: scg
        key-store-password: scg1234
        key-store: classpath:scg-keystore.p12
        key-store-type: PKCS12
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    网关路由可以路由到HTTP和HTTPS后端。如果路由到HTTPS后端,则可以将网关配置为信任所有具有证书的下游服务:

    Example 63. application.yml

    spring:
      cloud:
        gateway:
          httpclient:
            ssl:
              useInsecureTrustManager: true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    不建议在生产环境使用不安全的信任管理器。对于生产部署,可以使用一组已知证书配置网关,这些证书可以通过以下方式进行配置:

    Example 64. application.yml

    spring:
      cloud:
        gateway:
          httpclient:
            ssl:
              trustedX509Certificates:
              - cert1.pem
              - cert2.pem
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    如果Spring Cloud Gateway未配置受信任证书,则使用默认信任库(可以使用系统属性javax.net.ssl.trustStore覆盖)。

    9.1 TLS握手

    网关会维护一个用于路由到后端的client池。当通过HTTPS通信时,客户端启动一个TLS握手,其中可能会有很多超时。这些超时可以这样配置(显示默认值):

    Example 65. application.yml

    spring:
      cloud:
        gateway:
          httpclient:
            ssl:
              handshake-timeout-millis: 10000
              close-notify-flush-timeout-millis: 3000
              close-notify-read-timeout-millis: 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    10. Configuration

    Spring Cloud Gateway的配置由RouteDefinitionLocator的集合实例驱动。如下是RouteDefinitionLocator的接口:

    Example 66. RouteDefinitionLocator.java

    public interface RouteDefinitionLocator {
        Flux<RouteDefinition> getRouteDefinitions();
    }
    
    • 1
    • 2
    • 3

    默认情况下,PropertiesRouteDefinitionLocator使用Spring Boot的@ConfigurationProperties机制加载属性。

    以下两个方式等效:

    Example 67. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: setstatus_route
            uri: https://example.org
            filters:
            - name: SetStatus
              args:
                status: 401
          - id: setstatusshortcut_route
            uri: https://example.org
            filters:
            - SetStatus=401
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    对于网关的大部分用法,配置文件方式是够用的,但一些生产用例更建议从外部源(如数据库)加载配置。未来的里程碑版本将有基于Spring Data Repositories (如Redis、MongoDB和Cassandra)的RouteDefinitionLocator实现。

    10.1 RouteDefinition Metrics

    开启RouteDefinition,需要添加spring-boot-starter-actuator依赖。默认spring.cloud.gateway.metrics.enabled指标是设置为true。名为spring.cloud.gateway.routes.count的指标,其值为RouteDefinitions的值。指标路径/actuator/metrics/spring.cloud.gateway.routes.count

    11. Route Metadata Configuration

    您可以使用metadata为每个路由配置其他参数,如下所示:

    Example 68. application.yml

    spring:
      cloud:
        gateway:
          routes:
          - id: route_with_metadata
            uri: https://example.org
            metadata:
              optionName: "OptionValue"
              compositeObject:
                name: "value"
              iAmNumber: 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    您可以从exchange获取所有元数据属性,如下所示:

    Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
    // get all metadata properties
    route.getMetadata();
    // get a single metadata property
    route.getMetadata(someKey);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    12. Http超时配置

    12.1 全局超时

    connect-timeout 必填,毫秒
    response-timeout 必填,类型为 java.time.Duration

    global http timeouts example

    spring:
      cloud:
        gateway:
          httpclient:
            connect-timeout: 1000
            response-timeout: 5s
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    12.2 Per-route timeouts

    connect-timeout 必填,毫秒
    response-timeout必填,毫秒

          - id: per_route_timeouts
            uri: https://example.org
            predicates:
              - name: Path
                args:
                  pattern: /delay/{timeout}
            metadata:
              response-timeout: 200
              connect-timeout: 200
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    使用Java DSL配置 pre-route超时

    import static org.springframework.cloud.gateway.support.RouteMetadataUtils.CONNECT_TIMEOUT_ATTR;
    import static org.springframework.cloud.gateway.support.RouteMetadataUtils.RESPONSE_TIMEOUT_ATTR;
    
          @Bean
          public RouteLocator customRouteLocator(RouteLocatorBuilder routeBuilder){
             return routeBuilder.routes()
                   .route("test1", r -> {
                      return r.host("*.somehost.org").and().path("/somepath")
                            .filters(f -> f.addRequestHeader("header1", "header-value-1"))
                            .uri("http://someuri")
                            .metadata(RESPONSE_TIMEOUT_ATTR, 200)
                            .metadata(CONNECT_TIMEOUT_ATTR, 200);
                   })
                   .build();
          }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    per-route 的response-timeout为赋值的时候,全局的response-timeout将被禁用。

          - id: per_route_timeouts
            uri: https://example.org
            predicates:
              - name: Path
                args:
                  pattern: /delay/{timeout}
            metadata:
              response-timeout: -1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    12.3 流式Java Routes API

    RouteLocatorBuilder 具备流式API功能。

    Example 69. GatewaySampleApplication.java

    // static imports from GatewayFilters and RoutePredicates
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder, ThrottleGatewayFilterFactory throttle) {
        return builder.routes()
                .route(r -> r.host("**.abc.org").and().path("/image/png")
                    .filters(f ->
                            f.addResponseHeader("X-TestHeader", "foobar"))
                    .uri("http://httpbin.org:80")
                )
                .route(r -> r.path("/image/webp")
                    .filters(f ->
                            f.addResponseHeader("X-AnotherHeader", "baz"))
                    .uri("http://httpbin.org:80")
                    .metadata("key", "value")
                )
                .route(r -> r.order(-1)
                    .host("**.throttle.org").and().path("/get")
                    .filters(f -> f.filter(throttle.apply(1,
                            1,
                            10,
                            TimeUnit.SECONDS)))
                    .uri("http://httpbin.org:80")
                    .metadata("key", "value")
                )
                .build();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    这种风格运行更多的自定义断言,RouteDefinitionLocator 断言通过and组合。另外使用流式API,您可以使用and(), or(), 和negate()操作Predicate类。

    12.4 DiscoveryClient Route Definition Locator

    基于在DiscoveryClient兼容服务注册表中注册的服务创建路由。

    使用spring.cloud.gateway.discovery.locator.enabled=true开启它,并确保DiscoveryClient 实现组件(比如Netflix Eureka, Consul, or Zookeeper)在类路径中。

    12.4.1 Configuring Predicates and Filters For DiscoveryClient Routes

    Example 70. application.properties

    spring.cloud.gateway.discovery.locator.predicates[0].name: Path
    spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]: "'/'+serviceId+'/**'"
    spring.cloud.gateway.discovery.locator.predicates[1].name: Host
    spring.cloud.gateway.discovery.locator.predicates[1].args[pattern]: "'**.foo.com'"
    spring.cloud.gateway.discovery.locator.filters[0].name: CircuitBreaker
    spring.cloud.gateway.discovery.locator.filters[0].args[name]: serviceId
    spring.cloud.gateway.discovery.locator.filters[1].name: RewritePath
    spring.cloud.gateway.discovery.locator.filters[1].args[regexp]: "'/' + serviceId + '/?(?.*)'"
    spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    13. Reactor Netty 访问日志

    开启该访问日志,设置-Dreactor.netty.http.server.accessLogEnabled=true

    ❗️ 它是一个Java 系统配置,而不是Spring Boot的配置。

    您可以将日志记录系统配置为单独的访问日志文件。以下示例创建了一个Logback配置:

    Example 71. logback.xml

        <appender name="accessLog" class="ch.qos.logback.core.FileAppender">
            <file>access_log.logfile>
            <encoder>
                <pattern>%msg%npattern>
            encoder>
        appender>
        <appender name="async" class="ch.qos.logback.classic.AsyncAppender">
            <appender-ref ref="accessLog" />
        appender>
    
        <logger name="reactor.netty.http.server.AccessLog" level="INFO" additivity="false">
            <appender-ref ref="async"/>
        logger>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    14.CORS配置

    我们可以通过配置网关来控制CORS行为,全局CORS配置是 Spring Framework CorsConfiguration模式的URL MAP。

    Example 72. application.yml

    spring:
      cloud:
        gateway:
          globalcors:
            cors-configurations:
              '[/**]':
                allowedOrigins: "https://docs.spring.io"
                allowedMethods:
                - GET
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    例子中将允许从docs.spring.io发出的所有GET请求进行CORS请求。

    15. Actuator API

    /gateway的actuator端点允许监视Spring Cloud Gateway并与之交互。要进行远程访问,必须在应用程序属性中暴露HTTP或JMX 端口。

    Example 73. application.properties

    management.endpoint.gateway.enabled=true # default value
    management.endpoints.web.exposure.include=gateway
    
    • 1
    • 2

    15.1 Verbose Actuator Format

    它为每个路由添加了更多细节,允许您查看与每个路由相关联的谓词和过滤器以及可用的任何配置。

    [
      {
        "predicate": "(Hosts: [**.addrequestheader.org] && Paths: [/headers], match trailing slash: true)",
        "route_id": "add_request_header_test",
        "filters": [
          "[[AddResponseHeader X-Response-Default-Foo = 'Default-Bar'], order = 1]",
          "[[AddRequestHeader X-Request-Foo = 'Bar'], order = 1]",
          "[[PrefixPath prefix = '/httpbin'], order = 2]"
        ],
        "uri": "lb://testservice",
        "order": 0
      }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    该功能默认开启,如下设置禁用

    Example 74. application.properties

    spring.cloud.gateway.actuator.verbose.enabled=false
    
    • 1

    15.2 查询 Route Filters

    15.2.1 Global Filters

    要查询用于所有路由的全局filter,需要发送一个GET请求到/actuator/gateway/globalfilters。结果响应类似于以下内容:

    {
      "org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@77856cc5": 10100,
      "org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@4f6fd101": 10000,
      "org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@32d22650": -1,
      "org.springframework.cloud.gateway.filter.ForwardRoutingFilter@106459d9": 2147483647,
      "org.springframework.cloud.gateway.filter.NettyRoutingFilter@1fbd5e0": 2147483647,
      "org.springframework.cloud.gateway.filter.ForwardPathFilter@33a71d23": 0,
      "org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@135064ea": 2147483637,
      "org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@23c05889": 2147483646
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    对于每个全局过滤器,使用过滤器对象字符串表示,后面数字表示过滤器顺序。

    15.2.2 Route Filters

    要查询gateway Filters ,需要发送一个GET请求到/actuator/gateway/routefilters

    结果响应类似于以下内容:

    {
      "[AddRequestHeaderGatewayFilterFactory@570ed9c configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null,
      "[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]": null,
      "[SaveSessionGatewayFilterFactory@4449b273 configClass = Object]": null
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    每个工厂都有对应对象的字符串表示。null 是由于端点控制器的实现不完整,因为它试图设置过滤器链中对象的顺序,但这不适用于GatewayFilter工厂对象。

    15.3 刷新 Route Cache

    清除route cache ,发送POST请求到/actuator/gateway/refresh。请求返回一个200,没有响应主体。

    15.4 检索网关中定义的路由

    要检索网关中定义的路由,请向/actuator/gateway/routes发出GET请求。结果响应类似于以下内容:

    [{
      "route_id": "first_route",
      "route_object": {
        "predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@1e9d7e7d",
        "filters": [
          "OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.PreserveHostHeaderGatewayFilterFactory$$Lambda$436/674480275@6631ef72, order=0}"
        ]
      },
      "order": 0
    },
    {
      "route_id": "second_route",
      "route_object": {
        "predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@cd8d298",
        "filters": []
      },
      "order": 0
    }]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    响应包含网关中定义的所有路由的详细信息。下表描述了响应的每个元素(每个元素都是一个路由)的结构:

    PathTypeDescription
    route_idStringroute ID.
    route_object.predicateObjectroute 断言.
    route_object.filtersArray应用到该路由的 GatewayFilter factories
    orderNumberroute order.

    15.5 检索有关特定路由的信息

    要获取单个路由的信息,发送GET请求 /actuator/gateway/routes/{id} (如: /actuator/gateway/routes/first_route),返回结果如下所示:

    {
      "id": "first_route",
      "predicates": [{
        "name": "Path",
        "args": {"_genkey_0":"/first"}
      }],
      "filters": [],
      "uri": "https://www.uri-destination.org",
      "order": 0
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    下面表格中描述了返回结果信息:

    PathTypeDescription
    idStringroute ID.
    predicatesArray路由断言的集合。每个项定义给定断言的名称和参数。
    filtersArray应用于路由的过滤器器集合。
    uriString路由的目标URI
    orderNumberroute order.

    15.6 创建和删除特定路由

    要创建一个路由,发送POST请求 /gateway/routes/{id_route_to_create},参数为JSON结构,具体参数数据结构参考上面章节。
    要删除一个路由,发送 DELETE请求 /gateway/routes/{id_route_to_delete}

    15.7 所有端点列表

    下表总结了Spring Cloud Gateway启动器端点(注意,每个端点都有/actuator/gateway作为基础路径):

    IDHTTP MethodDescription
    globalfiltersGETDisplays the list of global filters applied to the routes.
    routefiltersGETDisplays the list of GatewayFilter factories applied to a particular route.
    refreshPOSTClears the routes cache.
    routesGETDisplays the list of routes defined in the gateway.
    routes/{id}GETDisplays information about a particular route.
    routes/{id}POSTAdds a new route to the gateway.
    routes/{id}DELETERemoves an existing route from the gateway.

    15.8 多个网关实例之间共享路由

    Spring Cloud Gateway 提供了两个RouteDefinitionRepository 实现。第一个是RouteDefinitionRepository 它只存在于一个网关实例的内存中。这种类型的存储库不适合跨多个网关实例填充路由。

    为了能够共享路由,可以使用RedisRouteDefinitionRepository 。要启用此类存储库,必须将以下属性设置为true:spring.cloud.gateway.redis-route-definition-repository.enabled,它需要使用spring-boot-starter-data-redis-reactive Spring Boot starter。

    16. 故障诊断

    16.1 Log Levels

    以下日志可能包含debug和trace级别的有价值的故障排除信息:

    org.springframework.cloud.gateway

    org.springframework.http.server.reactive

    org.springframework.web.reactive

    org.springframework.boot.autoconfigure.web

    reactor.netty

    redisratelimiter

    16.2 Wiretap

    Reactor Netty HttpClient 以及 HttpServer 可启用 Wiretap 。将reactor.netty 包设置成 debug 或 trace ,然后设置如下属性:

    spring.cloud.gateway.httpserver.wiretap=true
    spring.cloud.gateway.httpclient.wiretap=true

    分别开启HttpServer及HttpClient的Wiretap。

    17 开发者指南

    编写网关自定义组件基本指南。

    17.1 自定义Route Predicate Factories

    实现RoutePredicateFactory 作为bean,有一个AbstractRoutePredicateFactory 抽象类用于扩展。

    MyRoutePredicateFactory.java

    @Component
    public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {
    
        public MyRoutePredicateFactory() {
            super(Config.class);
        }
    
        @Override
        public Predicate<ServerWebExchange> apply(Config config) {
            // grab configuration from Config object
            return exchange -> {
                //grab the request
                ServerHttpRequest request = exchange.getRequest();
                //take information from the request to see if it
                //matches configuration.
                return matches(config, request);
            };
        }
    
        public static class Config {
            //Put the configuration properties for your filter here
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    17.2 自定义GatewayFilter Factories

    实现GatewayFilterFactory 作为一个bean,有一个抽象类AbstractGatewayFilterFactory用来扩展。

    Example 75. PreGatewayFilterFactory.java

    @Component
    public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> {
    
        public PreGatewayFilterFactory() {
            super(Config.class);
        }
    
        @Override
        public GatewayFilter apply(Config config) {
            // grab configuration from Config object
            return (exchange, chain) -> {
                //If you want to build a "pre" filter you need to manipulate the
                //request before calling chain.filter
                ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
                //use builder to manipulate the request
                return chain.filter(exchange.mutate().request(builder.build()).build());
            };
        }
    
        public static class Config {
            //Put the configuration properties for your filter here
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    PostGatewayFilterFactory.java

    @Component
    public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> {
    
        public PostGatewayFilterFactory() {
            super(Config.class);
        }
    
        @Override
        public GatewayFilter apply(Config config) {
            // grab configuration from Config object
            return (exchange, chain) -> {
                return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                    ServerHttpResponse response = exchange.getResponse();
                    //Manipulate the response in some way
                }));
            };
        }
    
        public static class Config {
            //Put the configuration properties for your filter here
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    17.2.1 在配置中命名自定义过滤器和引用

    自定义过滤器类名应以GatewayFilterFactory结尾。

    例如,要引用配置文件中名为Something 的过滤器,该过滤器必须位于名为SomethingGatewayFilterFactory的类中。

    17.3 自定义 Global Filters

    实现GlobalFilter 作为bean。

    以下示例分别显示了如何设置全局前置和后置过滤器:

    //前置
    @Bean
    public GlobalFilter customGlobalFilter() {
        return (exchange, chain) -> exchange.getPrincipal()
            .map(Principal::getName)
            .defaultIfEmpty("Default User")
            .map(userName -> {
              //adds header to proxied request
              exchange.getRequest().mutate().header("CUSTOM-REQUEST-HEADER", userName).build();
              return exchange;
            })
            .flatMap(chain::filter);
    }
    
    //后置
    @Bean
    public GlobalFilter customGlobalPostFilter() {
        return (exchange, chain) -> chain.filter(exchange)
            .then(Mono.just(exchange))
            .map(serverWebExchange -> {
              //adds header to response
              serverWebExchange.getResponse().getHeaders().set("CUSTOM-RESPONSE-HEADER",
                  HttpStatus.OK.equals(serverWebExchange.getResponse().getStatusCode()) ? "It worked": "It did not work");
              return serverWebExchange;
            })
            .then();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    18. 构建简单网关示例(略)

    19. 配置属性

    所有与Spring Cloud Gateway相关的配置列表

  • 相关阅读:
    打开网站显示“不安全”怎么办?
    elasticsearch bucket 之rare terms聚合
    【记录】终端如何 进入conda(base) 环境,如何退出 conda(base)环境,终端快速进入Jupyter notebook的方法
    JavaScript面向对象:面向对象案例
    精心总结十三条建议,帮你创建更合适的MySQL索引
    2022国产8K摄像机介绍
    2024-04-19 问AI: 介绍一下 Frobenius norm 在深度学习中的应用
    【第29例】IPD体系进阶:PL-TMT 产品线技术管理团队
    1:uniapp路由跳转
    从“pmp::indextype“转换到“const storageindex &“需要收缩转换
  • 原文地址:https://blog.csdn.net/weixin_40972073/article/details/125840118