文章目录

推荐

SpringCloud Gateway使用及原理分析大全(下篇)

spring cloud gateway官方文档介绍

下面文档基本就是官方文档的翻译,源自: SpringCloud Gateway使用及原理分析大全(下篇),做了一丢丢的补充

Spring Cloud Gateway夺命连环10问?

实战干货!Spring Cloud Gateway 整合 OAuth2.0 实现分布式统一认证授权!

我们理想的微服务权限解决方案应该是这样的,认证服务负责认证,网关负责校验认证和鉴权,其他API服务负责处理自己的业务逻辑。安全相关的逻辑只存在于认证服务和网关服务中,其他服务只是单纯地提供服务而没有任何安全相关逻辑。 - 代码

写在前面

Cloud全家桶中有个很重要的组件就是网关,在1.x版本中都是用的Zuul作为网关。 但是在2.x版本中,zuul的升级维护变得困难,SpringCloud最后自己研发了一个网关替代Zuul,那就是SpringCloud Gateway,使用gateway替代了zuul。

Gateway是在Spring生态系统之上构建的API网关服务,基于Spring5、SpringBoot2.0和Project Reactor等技术。 Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试等。

Spring Cloud Gateway需要Spring Boot和Spring Webflux提供的Netty运行环境。它不能在传统的Servlet容器中工作,也不能作为WAR来构建。

SpringCloud Gateway使用的Webflux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架。
在这里插入图片描述

一、熟悉Gateway基本概念与原理

1、三大概念

路由(Route):路由是构建网关的基本模块,它由ID、目标URI、一系列的断言过滤器组成,如果断言为true则匹配该路由。

断言(Predicate):参考Java8的java.util.function.Predicate,开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由。

过滤(Filter):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。

总的来说,web请求,通过一些匹配条件,定位到真正的服务节点,并在这个转发过程的前后,进行一些精细化控制。 prodicate就是我们的匹配条件;而filter可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标uri,就可以实现一个具体的路由了。

2、工作流程

客户端向Spring Cloud Gateway发出请求。如果网关处理程序映射确定一个请求与一个路由匹配,它将被发送到网关Web处理程序。该处理程序通过特定于请求的过滤器链运行请求。过滤器被虚线分开的原因是过滤器可以在发送代理请求之前和之后运行逻辑。执行所有“pre”过滤器逻辑。然后进行代理请求。发出代理请求后,将运行“post”过滤器逻辑。

注:在没有端口的路由中定义的URIs分别为HTTP和HTTPS URIs获得默认端口值80和443。

总结Gateway工作流程:

(1)客户端向SpringCloudGateway发出请求。然后在Gateway Handler Mapping中找到与请求相匹配的路由,将其发送到Gateway Web Handler

(2)Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。

(3)过滤器之间用虚线分开是因为过滤器可能会在发送代理请求==之前(pre)之后(post)==执行业务逻辑。

(4)Filter在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等。

(5)在“post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。

在这里插入图片描述

二、基本使用

1、pom配置

<!--gateway-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

注意:Gateway并不需要以下配置:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2、配置yml文件

server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          #uri: http://localhost:8001          #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由


        - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          #uri: http://localhost:8001          #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
            #- After=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
            #- Cookie=username,zzyy
            #- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式

eureka:
  instance:
    hostname: cloud-gateway-service
  client: #服务提供者provider注册进eureka服务列表内
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka.com:7001/eureka

路由断言的两种写法

1、简短断言

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - Cookie=mycookie,mycookievalue

2、完整断言

通常,会有一个name键和一个args键。args键是键值对的映射,用于配置断言或过滤器。

(1. 在GatewayAutoConfiguration中,定义了许多RoutePredicateFactory的bean,其中就有CookieRoutePredicateFactory

  1. CookieRoutePredicateFactory重写的shortcutFieldOrder方法中固定返回Arrays.asList(“name”, “regexp”);

  2. 如果后面有必要自己写断言工厂或这看其它断言工厂的写法含义可以查看这个)

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - name: Cookie
          args:
            name: mycookie
            regexp: mycookievalue

三、路由断言工厂

Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。

Spring Cloud Gateway包括许多内置的Route Predicate工厂。所有这些Predicate都与HTTP请求的不同属性匹配。多个Route Predicate工厂可以进行结合。

Spring Cloud Gateway创建Route对象时,使用RoutePredicateFactory创建Predicate对象,Predicate对象可以赋值给Route。Spring Cloud Gateway包含许多内置的Route Predicate Factiries。

所有这些断言(Predicate)都匹配HTTP请求的不同属性。多种断言工厂可以结合,并通过逻辑and。

1、After路由断言工厂

After 路由断言工厂接受一个参数datetime(java的ZonedDateTime)。该断言匹配在指定日期时间之后发生的请求。

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        # 东八区时间2022-09-25 15:00:00.000之后所有的请求,都会匹配到
        - After=2022-09-25T15:00:00.000+08:00[Asia/Shanghai]

2、Before路由断言工厂

Before 路由断言工厂接受一个参数datetime(java的ZonedDateTime)。该断言匹配在指定日期时间之前发生的请求。

spring:
  cloud:
    gateway:
      routes:
      - id: before_route
        uri: https://example.org
        predicates:
        # 东八区时间2022-09-25 15:00:00.000之前所有的请求,都会匹配到
        - Before=2022-09-25T15:00:00.000+08:00[Asia/Shanghai]

3、Between路由断言工厂

Between route断言工厂接受两个参数,datetime1和datetime2,它们是java ZonedDateTime对象。该断言匹配发生在datetime1之后和datetime2之前的请求。datetime2参数必须在datetime1之后。

spring:
  cloud:
    gateway:
      routes:
      - id: between_route
        uri: https://example.org
        predicates:
        # 东八区时间2022-09-25 15:00:00.000 到2022-09-26 15:00:00.000 之间的请求都会被匹配到
        - Between=2022-09-25T15:00:00.000+08:00[Asia/Shanghai], 2022-09-26T15:00:00.000+08:00[Asia/Shanghai]

4、Cookie路由断言工厂

cookie路由断言工厂接受两个参数,Cookie名称和一个regexp(Java正则表达式)。该谓词匹配具有给定名称并且其值匹配正则表达式的cookies。

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: https://example.org
        predicates:
        # cookie的key为mycookie,value为mycookievalue时会匹配到
        - Cookie=mycookie,mycookievalue

5、Header路由断言工厂

Header route断言工厂接受两个参数,Header和一个regexp(Java正则表达式)。该断言与具有给定名称的请求头匹配,该请求头的值与正则表达式匹配。

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: https://example.org
        predicates:
        # 请求头X-Request-Id的值为一个或多个数字,会被匹配到
        - Header=X-Request-Id, \d+

6、Host路由断言工厂

Host路由断言工厂接受一个参数:主机名表达式列表。用’.'作为分隔符。这个断言匹配与表达式匹配的主机头。

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: https://example.org
        predicates:
        # somehost.org结尾、anotherhost.org结尾的Host都能匹配到
        # 也支持URI模板变量(如{sub}.myhost.org)
        - Host=**.somehost.org,**.anotherhost.org

该断言提取URI模板变量(如{sub},在前面的示例中定义)作为名称和值的映射,并将其放入ServerWebExchange.getAttributes()中,并在ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE中定义一个键。这些值随后可供GatewayFilter工厂使用。

7、Method路由断言工厂

方法路由断言工厂接受一个方法参数,它是一个或多个参数——要匹配的HTTP方法。

spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: https://example.org
        predicates:
        # GET、POST请求会被匹配到
        - Method=GET,POST

8、Path路由断言工厂

路径路由断言工厂接受两个参数:一个Spring PathMatcher 表达式列表和一个名为matchTrailingSlash的可选标志(默认为true)。

spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: https://example.org
        predicates:
        # /red/1或/red/1/或/red/blue或/blue/green 都能匹配到
        - Path=/red/{segment},/blue/{segment}

如果matchTrailingSlash 设置了false,那么 /red/1/ 就匹配不到了。

该断言提取URI模板变量(如{segment},在前面的示例中定义)作为名称和值的映射,并将其放入ServerWebExchange.getAttributes()中,并在ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE中定义一个键。这些值随后可供GatewayFilter工厂使用

// 可以用以下方式获取变量参数
Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);
String segment = uriVariables.get("segment");

9、Query路由断言工厂

查询路由谓词工厂有两个参数:一个必需的参数和一个可选的regexp(Java正则表达式)。

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://example.org
        predicates:
        # 如果请求包含green查询参数,会被匹配到
        - Query=green
        # red、green、greet都能匹配到,支持正则
		# - Query=red, gree.

10、RemoteAddr 路由断言工厂

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

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: https://example.org
        predicates:
        # 192.168.1.10会被匹配到
        - RemoteAddr=192.168.1.1/24
修改远程地址的解析方式

默认情况下,RemoteAddr路由断言工厂使用来自传入请求的远程地址。如果Spring Cloud Gateway位于代理层之后,这可能与实际的客户端IP地址不匹配。

通过设置自定义RemoteAddressResolver,可以自定义解析远程地址的方式。Spring Cloud Gateway附带了一个非默认的远程地址解析器,它基于X-Forwarded-For Header,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值产生以下远程地址:

// 用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")
)

11、Weight 路由断言工厂

权重路由断言工厂接受两个参数:group和Weight(int类型)。权重按组计算。

spring:
  cloud:
    gateway:
      routes:
      # 这条路线将大约80%的流量转发到weighthigh.org,大约20%的流量转发到weighlow.org
      - id: weight_high
        uri: https://weighthigh.org
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: https://weightlow.org
        predicates:
        - Weight=group1, 2

12、XForwarded Remote Addr路由断言工厂

XForwarded Remote Addr route断言工厂接受一个源列表(最小大小为1),这些源是CIDR表示法(IPv4或IPv6)字符串,例如192.168.0.1/16(其中192.168.0.1是IP地址,16是子网掩码)。这个路由断言允许基于X-Forwarded-For HTTP头过滤请求。

这可以用于反向代理,如负载平衡器或web应用程序防火墙,其中只有当请求来自这些反向代理使用的IP地址的可信列表时,才应该允许该请求。

spring:
  cloud:
    gateway:
      routes:
      - id: xforwarded_remoteaddr_route
        uri: https://example.org
        predicates:
        # X-Forwarded-For报问头包含192.168.1.10等,则匹配
        - XForwardedRemoteAddr=192.168.1.1/24

四、GatewayFilter-网关过滤工厂

路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由过滤器的作用范围是特定的路由。Spring Cloud Gateway包括许多内置的GatewayFilter工厂。

1、AddRequestHeader 网关过滤工厂

AddRequestHeader 网关过滤工厂接受一个name和value参数。

(1. 在GatewayAutoConfiguration中,定义了许多GatewayFilterFactory的bean,其中就有AddRequestHeaderGatewayFilterFactory

  1. AddRequestHeaderGatewayFilterFactory继承自AbstractNameValueGatewayFilterFactory,默认重写的shortcutFieldOrder固定返回Arrays.asList(“name”, “value”);

  2. 如果后面有必要自己写网关过滤器工厂或这看其它网关过滤器工厂的写法含义可以查看这个)

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        filters:
        # 将X-Request-red:blue 请求头加入到所有下游的请求中
        - AddRequestHeader=X-Request-red, blue

(如下:使用Path断言提取的URI模板变量(如{segment},在前面的示例中定义)作为名称和值的映射,并将其放入ServerWebExchange.getAttributes()中,并在ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE中定义一个键。这些值随后可供GatewayFilter工厂使用)

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        predicates:
        - Path=/red/{
   segment}
        filters:
        # 也可以使用uri参数
        - AddRequestHeader=X-Request-Red, Blue-{segment}

2、AddRequestParameter 网关过滤工厂

AddRequestParameter 网关过滤工厂接受一个name和value参数。(可以看它是如何替换请求参数的

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_parameter_route
        uri: https://example.org
        filters:
        # 为所有匹配的请求 向下游请求的查询参数添加red=blue
        - AddRequestParameter=red, blue
spring:
  cloud:
    gateway:
      routes:
      - id: add_request_parameter_route
        uri: https://example.org
        predicates:
        - Host: {segment}.myhost.org
        filters:
        # 也可以使用url中的参数
        - AddRequestParameter=foo, bar-{segment}

3、AddResponseHeader 网关过滤工厂

AddResponseHeader GatewayFilter工厂接受一个name和value参数。(可以看它是怎么添加响应头的,它是在chain.doFilter(ServerWebExchange)前添加到exchange.getResponse().getHeaders()中的)

spring:
  cloud:
    gateway:
      routes:
      - id: add_response_header_route
        uri: https://example.org
        filters:
        # 这将X-Response-Red:Blue头添加到所有匹配请求的下游响应的头中。
        - AddResponseHeader=X-Response-Red, Blue
spring:
  cloud:
    gateway:
      routes:
      - id: add_response_header_route
        uri: https://example.org
        predicates:
        - Host: {segment}.myhost.org
        filters:
        # 也可以使用url中的参数
        - AddResponseHeader=foo, bar-{segment}

4、DedupeResponseHeader 网关过滤工厂

DedupeResponseHeader GatewayFilter 工厂接受一个名称参数和一个可选的策略参数。name可以包含以空格分隔的标头名称列表。(消除重复的响应头,在处理跨域时,可能会用到;从DedupeResponseHeaderGatewayFilterFactory中还可以看到在代理服务处理完逻辑之后作处理的then方法:chain.filter(exchange).then(Mono.fromRunnable(() -> dedupe(exchange.getResponse().getHeaders(), config))))

spring:
  cloud:
    gateway:
      routes:
      - id: dedupe_response_header_route
        uri: https://example.org
        filters:
        # 消除网关CORS逻辑和下游逻辑的Access-Control-Allow-Credentials、
        # Access-Control-Allow-Origin响应报头的重复值(注意:这里是用空格隔开)
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin

DedupeResponseHeader筛选器还接受一个可选的策略参数。接受的值为RETAIN_FIRST(默认值)、RETAIN_LAST和RETAIN_UNIQUE。

RETAIN_FIRST 默认值,保留第一个

RETANIN_LAST 保留最后一个

RETAIN_UNIQUE 保留唯一的,出现重复的属性值,会保留一个。例如有两个my:bbb的属性,最后会留一个。

5、SpringCloud断路器网关过滤工厂

Spring Cloud 断路器网关工厂使用Spring Cloud 断路器 API将网关路由包装在断路器中。Spring Cloud 断路器支持多个可以与Spring Cloud 网关一起使用的库。

要启用Spring Cloud 断路器过滤器,需要引入spring-cloud-starter-circuitbreaker-reactor-resilience4j依赖。 断路器官方文档:https://cloud.spring.io/spring-cloud-circuitbreaker/reference/html/spring-cloud-circuitbreaker.html

spring:
  cloud:
    gateway:
      routes:
      - id: circuitbreaker_route
        uri: https://example.org
        filters:
        - CircuitBreaker=myCircuitBreaker

Spring Cloud 断路器过滤器也可以接受一个可选的fallbackUri参数。目前,仅支持正向:计划的URI。如果调用回退,请求将被转发到URI匹配的控制器。

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
// 使用java配置
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
   
// 当调用断路器回退时,此示例转发到/inCaseofFailureUseThis。请注意,该示例还演示了(可选的)Spring Cloud LoadBalancer负载平衡(由目标URI上的lb前缀定义)。
    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();
}

主要场景是使用fallbackUri在网关应用程序中定义内部控制器或处理程序。

spring:
  cloud:
    gateway:
      routes:
      - id: ingredients
        uri: lb://ingredients
        predicates:
        - Path=//ingredients/**
		# 也可以将请求重新路由到外部应用程序中的控制器或处理程序,以下实例中网关应用程序中没有回退端点或处理程序。但是,在另一个应用程序中有一个,注册在localhost:9994下。	
        filters:
        - name: CircuitBreaker
          args:
            name: fetchIngredients
            fallbackUri: forward:/fallback
      - id: ingredients-fallback
        uri: http://localhost:9994
        predicates:
        - Path=/fallback

在请求被转发到回退的情况下,Spring Cloud 断路器网关过滤器还提供了导致它的Throwable。它作为ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR属性添加到ServerWebExchange中,在网关应用程序中处理回退时可以使用。

对于外部控制器/处理器场景,可以添加带有异常细节的头。可以参考FallbackHeaders 网关过滤工厂

根据状态代码使断路器跳闸

在某些情况下,可能希望根据断路器所环绕的路径返回的状态代码来触发断路器。断路器配置对象获取状态代码列表,如果返回,将导致断路器跳闸。当设置想要使断路器跳闸的状态代码时,可以使用带有状态代码值的整数,也可以使用HttpStatus枚举的字符串表示。

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"
// 使用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();
}

6、FallbackHeaders 网关过滤工厂

FallbackHeaders 工厂允许在转发给外部应用程序中的fallbackUri的请求的标头中添加Spring Cloud 断路器执行异常详细信息。

spring:
  cloud:
    gateway:
      routes:
      # 在运行断路器时发生执行异常后,请求被转发到在localhost:9994上运行的应用程序中的回退端点或处理程序。FallbackHeaders过滤器会将具有异常类型、消息和(如果可用)根本原因异常类型和消息的标头添加到该请求中。
      - 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

可以通过设置以下参数的值来覆盖配置中的标题名称(显示为默认值):

  • executionExceptionTypeHeaderName (“Execution-Exception-Type”)
  • executionExceptionMessageHeaderName (“Execution-Exception-Message”)
  • rootCauseExceptionTypeHeaderName (“Root-Cause-Exception-Type”)
  • rootCauseExceptionMessageHeaderName (“Root-Cause-Exception-Message”)

FallbackHeaders 网关过滤工厂用法和SpringCloud断路器网关过滤工厂 类似。

7、MapRequestHeader 网关过滤工厂

MapRequestHeader GatewayFilter工厂采用fromHeader和toHeader参数。它创建一个新的命名头(toHeader),并且从传入的http请求中的现有命名头(fromHeader)中提取值。如果输入头不存在,过滤器没有影响。如果新的命名头已经存在,它的值将增加新值。

spring:
  cloud:
    gateway:
      routes:
      - id: map_request_header_route
        uri: https://example.org
        filters:
        # 这将X-Request-Red:<values> 请求头添加到下游请求中,其中包含来自传入HTTP请求的Blue请求头的值。
        - MapRequestHeader=Blue, X-Request-Red

8、PrefixPath 网关过滤工厂

(就是给匹配当前路由的请求加上前缀)

spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://example.org
        filters:
        # 素有匹配的请求都会添加/mypath作为路径的前缀。比如/hello请求将被发送到/mypath/hello
        - PrefixPath=/mypath

9、PreserveHostHeader 网关过滤工厂

为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host Header。如果不设置,那么名为 Host 的Header将由Http Client控制。

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

10、RequestRateLimiter 网关过滤工厂

(在GatewayAutoConfiguration中定义了RequestRateLimiterGatewayFilterFactory这个bean,但是这个bean只有当容器中定义了RateLimiter和KeyResolver这个2个bean时->可以参看GatewayAutoConfigurationRedisAutoConfiguration,才会生效;GatewayAutoConfiguration中定义了PrincipalNameKeyResolver,它只有在容器中存在RateLimiter时,并且不存在KeyResolver时,才会生效。综合来看我们至少需要定义RateLimiter这个bean,可在有必要的时候定义KeyResolver这个bean来替换默认的PrincipalNameKeyResolver。最后,这2个bean都会设置到RequestRateLimiterGatewayFilterFactory中)

(在RequestRateLimiterGatewayFilterFactory中展示了如何结束响应:exchange.getResponse().setComplete())

RequestRateLimiter GatewayFilter工厂使用RateLimiter实现来确定是否允许当前请求继续进行。如果不是,则默认返回HTTP 429 - Too Many Requests状态。

该过滤器采用可选的keyResolver参数和rateLimiter特定的参数。

keyResolver是一个实现KeyResolver接口的bean。在配置中,使用SpEL通过名称引用bean。#{@myKeyResolver}是一个引用名为myKeyResolver的bean的SpEL表达式。

// KeyResolver 接口
public interface KeyResolver {
   
    Mono<String> resolve(ServerWebExchange exchange);
}

KeyResolver接口让可插拔策略派生出限制请求的密钥。在未来的版本中,将会有一些KeyResolver实现。

KeyResolver的默认实现是PrincipalNameKeyResolver,它从ServerWebExchange检索主体并调用Principal.getName()。

默认情况下,如果KeyResolver没有找到密钥,请求将被拒绝。可以通过设置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不能用“快捷方式”符号进行配置。下面的例子是无效的:

# 无效的快捷配置
spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2, #{@userkeyresolver}
redis限流

Redis的实现基于Stripe所做的。它需要引入spring-boot-starter-data-redis-reactive依赖。使用的算法是令牌桶算法。

(引入spring-boot-starter-data-redis-reactive依赖后,GatewayRedisAutoConfiguration就会生效,里面定义了RedisRateLimiter,而RedisRateLimiter有使用@ConfigurationProperties(“spring.cloud.gateway.redis-rate-limiter”)来读取并设置属性,但实际的设置属性不是这样设置进去的)

redis-rate-limiter.replenishRate属性是允许用户每秒处理多少请求,而不丢弃任何请求,多余的请求排队处理。这是令牌桶的填充速率

redis-rate-limiter.burstCapacity属性是允许用户在一秒钟内进行的最大请求数。这是令牌桶可以容纳的令牌数。将该值设置为零会阻止所有请求。

redis-rate-limiter.requestedTokens属性是一个请求花费多少令牌。这是每个请求从桶中获取的令牌数,默认为1。

通过在replenishRate和burstCapacity中设置相同的值来实现稳定的速率

通过将burstCapacity设置为高于replenishRate,可以允许临时突发。在这种情况下,需要允许速率限制器在突发之间有一段时间(根据replenishRate),因为两个连续的突发将导致丢弃请求(HTTP 429 - Too Many Requests)。

低于1个请求/秒的速率限制是通过将replenishRate设置为所需的请求数,将requestedTokens设置为以秒为单位的时间跨度,将burstCapacity设置为replenishRate和requestedTokens的乘积来实现的,例如,设置replenishRate=1、requestedTokens=60和burstCapacity=60将导致1个请求/分钟的限制。

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
          	# 每秒最多处理10个请求,每秒最大20个请求,请求一次花费1个令牌
          	# 这定义了每个用户10的请求速率限制。允许20个突发,但是在下一秒,只有10个请求可用。
            redis-rate-limiter.replenishRate: 10  # 令牌桶的填充速率
            redis-rate-limiter.burstCapacity: 20  # 令牌桶可以容纳的令牌数
            redis-rate-limiter.requestedTokens: 1 # 一个请求花费多少令牌
// 使用java配置一个KeyResolver KeyResolver是一个简单的工具,它获取用户请求参数(注意,不建议在生产中使用)。
@Bean
KeyResolver userKeyResolver() {
   
    return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}
spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        # 还可以将速率限制器定义为实现RateLimiter 接口的bean。
        # 在配置中,可以使用SpEL通过名称引用bean。
        #         {@myRateLimiter}是一个引用名为myRateLimiter的bean的SpEL表达式。
        # 下面的清单定义了一个速率限制器,它使用前面清单中定义的KeyResolver
        - name: RequestRateLimiter
          args:
            rate-limiter: "#{@myRateLimiter}"
            key-resolver: "#{@userKeyResolver}"

11、RedirectTo 网关过滤工厂

RedirectTo GatewayFilter工厂有两个参数,status和url。status参数应该是300系列重定向HTTP代码,比如301。url参数应该是有效的URL。这是位置头的值。对于相对重定向,应该使用uri: no://op作为路由定义的uri。

spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://example.org
        filters:
        # 这将发送带有Location:https://acme.org头的状态302来执行重定向。
        - RedirectTo=302, https://acme.org

12、RemoveRequestHeader 网关过滤工厂

RemoveRequestHeader gateway filter工厂接受一个名称参数。这是要删除的请求头的名称。

spring:
  cloud:
    gateway:
      routes:
      - id: removerequestheader_route
        uri: https://example.org
        filters:
        # 网下游发请求时,删除X-Request-Foo 请求头
        - RemoveRequestHeader=X-Request-Foo

13、RemoveResponseHeader 网关过滤工厂

RemoveResponseHeader gateway filter工厂接受一个名称参数。这是要删除的请求头的名称。

spring:
  cloud:
    gateway:
      routes:
      - id: removeresponseheader_route
        uri: https://example.org
        filters:
        # 在响应返回前 删除X-Response-Foo请求头。
        - RemoveResponseHeader=X-Response-Foo

注意:要删除任何类型的敏感请求头,应该为想要删除的任何路由配置此过滤器。 此外,您可以使用spring.cloud.gateway.default-filters配置此过滤器一次,并将其应用于所有路由

14、RemoveRequestParameter网关过滤工厂

RemoveRequestParameter gateway filter工厂接受一个名称参数。这是要删除的查询参数的名称。

spring:
  cloud:
    gateway:
      routes:
      - id: removerequestparameter_route
        uri: https://example.org
        filters:
        # 往下游系统发送的请求,都删掉red参数
        - RemoveRequestParameter=red

15、RequestHeaderSize 网关过滤 工厂

RequestHeaderSize GatewayFilter工厂采用maxSize和errorHeaderName参数。

maxSize参数是请求标头中允许的最大数据大小(包括键和值)。

errorHeaderName参数设置包含错误消息的响应头的名称,默认情况下为“error message”。

(RequestHeaderSizeGatewayFilterFactory中示范了在接收到客户端请求时,遍历客户端请求的每个请求头的大小,当有请求头的大小超过指定大小时,提前结束请求,并返回指定的响应状态码

spring:
  cloud:
    gateway:
      routes:
      - id: requestheadersize_route
        uri: https://example.org
        filters:
        # 如果任何请求报头的大小大于1000字节,这将发送状态431。
        - RequestHeaderSize=1000B

16、RewritePath 网关过滤工厂

RewritePath GatewayFilter工厂接受一个路径regexp参数和一个替换参数。这使用Java正则表达式以灵活的方式重写请求路径。

spring:
  cloud:
    gateway:
      routes:
      - id: rewritepath_route
        uri: https://example.org
        predicates:
        	- Path=/red/**
        filters:
        # 对于/red/blue请求路径,这将在发出下游请求之前将路径设置为/blue。请注意,根据YAML规范,$应该替换为$\。
        - RewritePath=/red/?(?<segment>.*), /$\{segment}

17、RewriteLocationResponseHeader 网关过滤器

RewriteLocationResponseHeader gateway filter工厂修改位置响应头的值,通常是为了消除后端特定的细节。

它采用stripVersionMode、locationHeaderName、hostValue和protocolsRegex参数。

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

比如,一个post请求api.example.com/some/object/name,Location 的响应头object-service.prod.example.net/v2/some/object/id值会被重写为api.example.com/some/object/id

stripVersionMode参数有以下可能值:NEVER_STRIP、AS_IN_REQUEST(默认值)和ALWAYS_STRIP。

  • NEVER_STRIP:不剥离版本,即使原始请求路径不包含版本。
  • AS_IN_REQUEST仅当原始请求路径不包含版本时,才剥离版本。
  • LWAYS_STRIP总是剥离版本,即使原始请求路径包含版本。

hostValue参数(如果提供)用于替换响应位置标头的host:port部分。如果没有提供,则使用主机请求头的值。 protocolsRegex参数必须是有效的Regex字符串,协议名称与之匹配。如果不匹配,过滤器什么也不做。默认为http|https|ftp|ftps。

18、RewriteResponseHeader 网关过滤工厂

RewriteResponseHeader gateway filter工厂接受name、正则表达式和replacement参数。

它使用Java正则表达式以灵活的方式重写响应头值。

spring:
  cloud:
    gateway:
      routes:
      - id: rewriteresponseheader_route
        uri: https://example.org
        filters:
        # 一个头的值为 /42?user=ford&password=omg!what&flag=true,在发出下游请求后,将此头设置为 /42?user=ford&password=***&flag=true。注意使用 $\ 代表 $,这是 YAML 格式指定的。
        - RewriteResponseHeader=X-Response-Red, , password=[^&]+, password=***

19、SaveSession 网关过滤工厂

在向下游转发调用之前,SaveSession GatewayFilter工厂强制执行WebSession::save操作。这在使用类似Spring Session的惰性数据存储时特别有用,需要确保在进行转发调用之前保存会话状态。

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

如果将Spring安全性与Spring Session集成在一起,并希望确保安全性细节已经被转发到远程进程,这一点非常重要。

20、SecureHeaders 网关过滤工厂

SecureHeaders GatewayFilter工厂 根据这篇博客文章中的建议向响应添加了许多请求头。

  • 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属性:

# 需要使用安全标头的小写全名来禁用它
spring.cloud.gateway.filter.secure-headers.disable=x-frame-options,strict-transport-security

21、SetPath 网关过滤工厂

SetPath GatewayFilter工厂采用路径模板参数。它提供了一种简单的方法,通过允许路径的模板段来操作请求路径。这使用了Spring框架中的URI模板。允许多个匹配段。

spring:
  cloud:
    gateway:
      routes:
      # 对于/red/blue请求路径,这将在发出下游请求之前将路径设置为/blue。
      - id: setpath_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment}
        filters:
        - SetPath=/{segment}

22、SetRequestHeader 网关过滤工厂

SetRequestHeader GatewayFilter工厂接受name和value参数。

spring:
  cloud:
    gateway:
      routes:
      - id: setrequestheader_route
        uri: https://example.org
        filters:
        # X-Request-Red:1234 下游请求头将会被替换为X-Request-Red:Blue
        - SetRequestHeader=X-Request-Red, Blue
spring:
  cloud:
    gateway:
      routes:
      - id: setrequestheader_route
        uri: https://example.org
        predicates:
        - Host: {segment}.myhost.org
        filters:
        # 也可以使用path路径上的参数
        - SetRequestHeader=foo, bar-{segment}

23、SetResponseHeader 网关过滤工厂

SetResponseHeader GatewayFilter工厂接受name和value参数。

spring:
  cloud:
    gateway:
      routes:
      - id: setresponseheader_route
        uri: https://example.org
        filters:
        # X-Request-Red:1234 下游响应头将会被替换为X-Request-Red:Blue
        - SetResponseHeader=X-Response-Red, Blue
spring:
  cloud:
    gateway:
      routes:
      - id: setresponseheader_route
        uri: https://example.org
        predicates:
        - Host: {segment}.myhost.org
        filters:
        # 也可以使用path路径上的参数
        - SetResponseHeader=foo, bar-{segment}

24、SetStatus 网关过滤工厂

SetStatus GatewayFilter工厂接受单个参数Status。它必须是有效的Spring HttpStatus。它可以是整数值404或枚举的字符串表示:NOT_FOUND。

spring:
  cloud:
    gateway:
      routes:
      # 在这两种情况下,响应的HTTP状态都设置为401。
      - id: setstatusstring_route
        uri: https://example.org
        filters:
        - SetStatus=UNAUTHORIZED
      - id: setstatusint_route
        uri: https://example.org
        filters:
        - SetStatus=401
# 可以将SetStatus GatewayFilter配置为在响应的标头中返回代理请求的原始HTTP状态代码。如果使用以下属性进行配置,标头将被添加到响应中:
spring:
  cloud:
    gateway:
      set-status:
        original-status-header-name: original-http-status

25、StripPrefix 网关过滤工厂

StripPrefix GatewayFilter工厂接受一个参数parts。parts参数指示在将请求发送到下游之前,路径中要从请求中去除的部分的数量。

spring:
  cloud:
    gateway:
      routes:
      # 当通过网关向/name/blue/red发出请求时,向nameservice发出的请求看起来像nameservice/red。
      - id: nameRoot
        uri: https://nameservice
        predicates:
        - Path=/name/**
        filters:
        - StripPrefix=2

26、Retry 网关过滤工厂

重试网关过滤器工厂支持以下参数:

  • retries:应该尝试的重试次数
  • statuses:应该重试的状态码,用org.springframework.http.HttpStatus表示。
  • methods:应该重试的HTTP方法,org.springframework.http.HttpMethod。
  • series:要重试的状态代码系列,用org.springframework.http.HttpStatus.Series表示。
  • exceptions:应该重试的引发异常的列表。
  • backoff:为重试配置的指数补偿。在firstBackoff * (factor ^ n)的补偿间隔之后执行重试,其中n是迭代。如果配置了maxBackoff,则应用的最大回退限制为maxBackoff。如果basedOnPreviousValue为true,则通过使用prevBackoff * factor来计算补偿。

如果启用了重试过滤器,则为其配置以下默认值:

  • retries:三次。
  • series:5xx状态码。
  • methods:Get方法
  • exceptions:IOException 和TimeoutException
  • backoff:未开启
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
# 简写 对比
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

27、RequestSize 网关过滤器

当请求大小大于允许的限制时,RequestSize GatewayFilter工厂可以限制请求到达下游服务。该筛选器采用maxSize参数。maxSize是一种数据大小类型,因此可以将值定义为一个数字,后跟一个可选的数据单元后缀,如“KB”或“MB”。字节的默认值为“B”。这是以字节定义的请求的允许大小限制。

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

当请求因大小而被拒绝时,RequestSize GatewayFilter工厂将响应状态设置为413 Payload Too Large,并附加一个报头errorMessage。

errorMessage : Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB

如果没有在路由定义中作为过滤器参数提供,则默认请求大小被设置为5mb。

28、SetRequestHostHeader 网关过滤器

在某些情况下,主机标头可能需要被覆盖。在这种情况下,SetRequestHostHeader gateway filter工厂可以用指定的值替换现有的主机头。过滤器接受一个主机参数。

spring:
  cloud:
    gateway:
      routes:
      - id: set_request_host_header_route
        uri: http://localhost:8080/headers
        predicates:
        - Path=/headers
        filters:
        # SetRequestHostHeader gateway filter工厂将主机头的值替换为example.org。
        - name: SetRequestHostHeader
          args:
            host: example.org

29、ModifyRequestBody 网关过滤器

可以使用ModifyRequestBody过滤器在网关向下游发送请求正文之前对其进行修改。

这个过滤器只能通过使用Java DSL来配置。

// 修改请求正文
// 如果请求没有正文,RewriteFilter将被传递为null。应该返回Mono.empty()来分配请求中缺少的主体。
@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) -> 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;
    }
}

30、ModifyResponseBody 网关过滤器

可以使用ModifyResponseBody过滤器在响应正文被发送回客户端之前对其进行修改。

这个过滤器只能通过使用Java DSL来配置。

// 修改响应正文
// 如果请求没有正文,RewriteFilter将被传递为null。应该返回Mono.empty()来分配请求中缺少的主体。
@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();
}



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

31、Token Relay网关过滤器

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

Spring Cloud Gateway可以将OAuth2访问令牌向下游转发给它所代理的服务。要将此功能添加到网关,您需要像这样添加TokenRelayGatewayFilterFactory:

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
   
    return builder.routes()
                 	 .route("resource", r -> r.path("/resource")
                                              .filters(f -> f.tokenRelay())
                                              .uri("http://localhost:9000")
                      )
                	 .build();
}

或者使用yml配置

spring:
  cloud:
    gateway:
      routes:
      - id: resource
        uri: http://localhost:9000
        predicates:
        - Path=/resource
        filters:
        - TokenRelay=

它还会(除了让用户登录并获取令牌之外)将身份验证令牌向下游传递给服务(在本例中为/resource)。 要为Spring Cloud Gateway实现这一点,需要添加以下依赖项:

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

它是如何工作的?

{githubmaster}/src/main/java/org/springframework/cloud/gateway/security/TokenRelayGatewayFilterFactory.java[filter]从当前通过身份验证的用户中提取一个访问令牌,并将其放入下游请求的请求标头中。

32、CacheRequestBody 网关过滤器

有某些情况需要读正文。因为请求体流只能被读取一次,所以我们需要缓存请求体。 可以使用CacheRequestBody过滤器在请求正文发送到下游之前对其进行缓存,并从exchagne属性中获取正文。

// 进行缓存
@Bean
@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();
}
# 进行缓存
spring:
  cloud:
    gateway:
      routes:
      - id: cache_request_body_route
        uri: lb://downstream   # lb://开头表示从注册中心拉取服务, 并且负载均衡
        predicates:
        - Path=/downstream/**
        filters:
        - name: CacheRequestBody
          args:
            bodyClass: java.lang.String

CacheRequestBody将提取请求体,并将其转换为Body类(如前面的示例中定义的java.lang.String)。然后用ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR中定义的键将其放入ServerWebExchange.getAttributes()中。

此过滤器仅适用于http请求(包括https)。

33、 JSONToGRPC网关过滤器

JSONToGRPCFilter GatewayFilter工厂将JSON有效负载转换为gRPC请求。

该过滤器采用以下参数: protoDescriptor :原型描述符文件。

可以使用指定–descriptor_set_out标志的协议生成该文件:

protoc --proto_path=src/main/resources/proto/ \
--descriptor_set_out=src/main/resources/proto/hello.pb  \
src/main/resources/proto/hello.proto
  • protoFile :原型定义文件
  • service :将处理请求的服务的完全限定名。
  • method :服务中处理请求的方法名。

注意:不支持streaming 。

@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
   
    return builder.routes()
            .route("json-grpc", r -> r.path("/json/hello").filters(f -> {
   
                String protoDescriptor = "file:src/main/proto/hello.pb";
                String protoFile = "file:src/main/proto/hello.proto";
                String service = "HelloService";
                String method = "hello";
                return f.jsonToGRPC(protoDescriptor, protoFile, service, method);
            }).uri(uri))
spring:
  cloud:
    gateway:
      routes:
        - id: json-grpc
          uri: https://localhost:6565/testhello
          predicates:
            - Path=/json/**
          filters:
            - name: JsonToGrpc
              args:
                protoDescriptor: file:proto/hello.pb
                protoFile: file:proto/hello.proto
                service: com.example.grpcserver.hello.HelloService
                method: hello

当通过网关向/json/hello发出请求时,请求将使用hello.proto中提供的定义进行转换,发送到com.example.grpcserver.hello.HelloService/hello,,并将响应转换回json。

默认情况下,它将使用默认的TrustManagerFactory创建一个NettyChannel。但是,可以通过创建GrpcSslConfigurer类型的bean来定制这个信任管理器:

@Configuration
public class GRPCLocalConfiguration {
   
    @Bean
    public GRPCSSLContext sslContext() {
   
        TrustManager trustManager = trustAllCerts();
        return new GRPCSSLContext(trustManager);
    }
}

34、Default过滤器

要添加过滤器并将其应用于所有路由,您可以使用spring.cloud.gateway.default-filters

该属性接受一个筛选器列表。以下清单定义了一组默认过滤器:

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

五、GlobalFilter-全局过滤器

GlobalFilter接口与GatewayFilter具有相同的方法签名(方法签名都是:Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain))。这些是有条件地应用于所有路由的特殊过滤器(有条件的意思是指:以下这些全局过滤器会在特定的时候才起作用)。

在未来的里程碑版本中,该接口及其用法可能会有所变化。

1、组合全局过滤器和网关过滤器排序

当请求与路由匹配时,筛选web处理程序会将GlobalFilter的所有实例GatewayFilter的所有路由特定实例都添加到过滤器链中。这个组合的过滤器链由org.springframework.core.Ordered接口排序,您可以通过实现getOrder()方法来设置该接口。

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

// 配置一个过滤器链
@Bean
public GlobalFilter customFilter() {
   
    return new CustomGlobalFilter();
}

// 通过实现order接口来实现排序
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;
    }
}

2、转发路由过滤器

ForwardRoutingFilter在exchange属性ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR中查找URI。

如果URL有转发方案(比如forward:///localendpoint),它就会使用Spring DispatcherHandler来处理请求。

请求URL的路径部分被转发URL中的路径覆盖。

未修改的原始URL被附加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR中的列表。

3、ReactiveLoadBalancerClientFilter(lb负载均衡)

需要引入spring-cloud-starter-loadbalancer依赖,因为ReactiveLoadBalancerClientFilter有依赖ReactorLoadBalancer、LoadBalancerClientFactory

ReactiveLoadBalancerClientFilter在名为ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR属性中查找URI。

如果URL有lb方案(比如lb://myservice),它使用Spring Cloud ReactorLoadBalancer将名称(本例中为myservice)解析为实际的主机和端口,并替换相同属性中的URI。

未修改的原始URL被附加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR中的列表.

该筛选器还会在ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR中查找属性,看是否等于lb。如果是这样,同样的规则也适用。

spring:
  cloud:
    gateway:
      routes:
      - id: myRoute
        uri: lb://service # 负载均衡调用
        predicates:
        - Path=/service/**

默认情况下,当ReactorLoadBalancer找不到服务实例时,将返回503(这个就不陌生了,当服务还在启动,还没注册到注册中心时,或者还没拉取到服务,就是返回的503)。通过设置spring.cloud.gateway.loadbalancer.use404=true,可以将网关配置为返回404。

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

4、Netty路由过滤器

如果位于ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR的 exchange属性中的URL具有http或https方案,则Netty路由过滤器将运行。它使用Netty HttpClient发出下游代理请求。响应放在ServerWebExchangeUtils中。CLIENT_RESPONSE_ATTR交换属性,以便在以后的过滤器中使用。(还有一个实验性的WebClientHttpRoutingFilter,它执行相同的功能,但不需要Netty。)

5、NettyWriteResponseFilter

如果ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR中有Netty HttpClientResponse,则NettyWriteResponseFilter将运行。它在所有其他过滤器完成后运行,并将代理响应写回网关客户端响应。(还有一个实验性的WebClientWriteResponseFilter,它执行相同的功能,但不需要Netty)

6、RouteToRequestUrl 过滤器

如果ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR中有路由对象,则运行RouteToRequestUrlFilter。它基于请求URI创建了一个新的URI,但是用路由对象的URI属性进行了更新。新的URI放在ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR中。

7、Websocket Routing 过滤器

(这个WebsocketRoutingFilter也是在GatewayAutoConfiguration中定义的bean)

如果位于ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR exchange属性中的URL具有ws或wss方案,websocket路由过滤器将运行(也就是说:这些全局过滤器是有条件运行的,在我们指定使用ws时,这个全局过滤器才生效)。它使用Spring WebSocket基础设施向下游转发WebSocket请求。

可以通过在URI前面加上lb来对websockets进行负载平衡,比如lb:ws://serviceid。

如果使用SockJS作为普通HTTP的后备,那么应该配置一个普通HTTP路由以及websocket路由(如下所示配置)。

# 配置一个websocket 路由过滤器
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/**

8、Gateway Metrics Filter

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

  • routeId:路由ID
  • routeUri:API被路由到的URI。
  • outcome:由HttpStatus.Series分类的结果
  • status:返回给客户端的请求的HTTP状态。
  • httpStatusCode:返回给客户端的请求的HTTP状态。
  • httpMethod:用于请求的HTTP方法。

此外,通过属性spring.cloud.gateway.metrics.tags.path.enabled(默认情况下,设置为false),您可以使用标记激活额外的指标:

  • path:请求的路径。

这些指标可以从/actuator/metrics/spring.cloud.gateway.requests中获取,并可以轻松地与Prometheus集成以创建Grafana仪表板。

要启用prometheus端点,请添加micrometer-registry-prometheus作为项目依赖项。

9、将Exchange 标记为 Routed(已路由)

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

  • ServerWebExchangeUtils.isAlreadyRouted接受一个ServerWebExchange对象并检查它是否已被“路由”。
  • ServerWebExchangeUtils.setAlreadyRouted接受一个ServerWebExchange对象,并将其标记为“已路由”。

六、HttpHeadersFilters

HttpHeadersFilters在将请求发送到下游之前应用于请求,例如在NettyRoutingFilter中。

1、Forwarded Headers Filter

转发头过滤器创建一个转发头发送到下游服务。它将当前请求的主机请求头、方案和端口添加到任何现有的转发请求头中。

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属性设置为要删除的请求头名称列表。

3、XForwarded Headers Filter

XForwarded Headers筛选器创建各种X-Forwarded-*标头以发送到下游服务。它使用当前请求的主机头、方案、端口和路径来创建各种头。

单个标题的创建可由以下布尔属性控制(默认为true):

  • spring.cloud.gateway.x-forwarded.for-enabled
  • spring.cloud.gateway.x-forwarded.host-enabled
  • spring.cloud.gateway.x-forwarded.port-enabled
  • spring.cloud.gateway.x-forwarded.proto-enabled
  • spring.cloud.gateway.x-forwarded.prefix-enabled

追加多个标题可以由以下布尔属性控制(默认为true):

  • spring.cloud.gateway.x-forwarded.for-append
  • spring.cloud.gateway.x-forwarded.host-append
  • spring.cloud.gateway.x-forwarded.port-append
  • spring.cloud.gateway.x-forwarded.proto-append
  • spring.cloud.gateway.x-forwarded.prefix-append

七、TLS 和SSL

网关可以通过遵循通常的Spring服务器配置来监听HTTPS上的请求。

server:
  ssl:
    enabled: true
    key-alias: scg
    key-store-password: scg1234
    key-store: classpath:scg-keystore.p12
    key-store-type: PKCS12

可以将网关路由路由到HTTP和HTTPS后端。如果要路由到HTTPS后端,可以使用以下配置将网关配置为信任所有下游证书:

spring:
  cloud:
    gateway:
      httpclient:
        ssl:
          useInsecureTrustManager: true

使用不安全的信任管理器不适合生产。对于生产部署,可以使用一组它可以信任的已知证书来配置网关,配置如下:

spring:
  cloud:
    gateway:
      httpclient:
        ssl:
          trustedX509Certificates:
          - cert1.pem
          - cert2.pem

如果Spring Cloud Gateway没有提供可信证书,则使用默认的信任存储(可以通过设置javax.net.ssl.trustStore系统属性来覆盖它)。

TLS 握手

网关维护一个客户端池,用于路由到后端。当通过HTTPS通信时,客户端发起TLS握手。许多超时与该握手相关联。可以按如下方式配置这些超时值(显示默认值):

spring:
  cloud:
    gateway:
      httpclient:
        ssl:
          handshake-timeout-millis: 10000
          close-notify-flush-timeout-millis: 3000
          close-notify-read-timeout-millis: 0

八、配置-Configuration

Spring Cloud Gateway的配置是由RouteDefinitionLocator实例的集合来驱动的。

// RouteDefinitionLocator接口的定义
public interface RouteDefinitionLocator {
   
    Flux<RouteDefinition> getRouteDefinitions();
}

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

前面的配置示例都使用一种快捷表示法,它使用位置参数,而不是命名参数。以下两个示例是等效的:

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

对于网关的某些用途,属性是足够的,但是某些生产用例从外部源(如数据库)加载配置。未来的里程碑版本将会有基于Spring Data Repository的RouteDefinitionLocator实现,比如Redis、MongoDB和Cassandra。

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获得。

九、Route Metadata Configuration-路由元数据配置

(类似于Vue-Router中从路由中获取meta元数据)

# 可以使用元数据为每个路径配置附加参数
spring:
  cloud:
    gateway:
      routes:
      - id: route_with_metadata
        uri: https://example.org
        metadata:
          optionName: "OptionValue"
          compositeObject:
            name: "value"
          iAmNumber: 1
// 可以从exchange中获取所有元数据属性
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);

// get all metadata properties
route.getMetadata();

// get a single metadata property
route.getMetadata(someKey);

十、Http超时配置

可以为所有路由配置Http超时(响应和连接),并为每个特定路由覆盖。

1、全局超时设置

要配置全局http超时:

  • connect-timeout:必须以毫秒为单位指定。
  • response-timeout:必须指定为java.time.Duration。
# 配置全局超时
spring:
  cloud:
    gateway:
      httpclient:
        connect-timeout: 1000
        response-timeout: 5s

2、配置每个路由的超时

要配置每路由超时:

  • 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
// 使用java为每个路由设置超时
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();
      }
# 注意:当单个路由设置response-timeout为负值时,将会禁用全局的response-timeout。
      - id: per_route_timeouts
        uri: https://example.org
        predicates:
          - name: Path
            args:
              pattern: /delay/{timeout}
        metadata:
          response-timeout: -1

十一、Java路由API

为了在Java中实现简单的配置,RouteLocatorBuilder bean引入了一个流畅的API。

// 静态引入 GatewayFilters 和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();
}

这种风格还允许更多的自定义断言。RouteDefinitionLocator beans定义的断言使用逻辑and进行组合,通过使用 Java API,您可以在谓词类上使用and()、or()和negate()运算符。

十二、DiscoveryClient客户端路径定义定位器

开启注册中心的服务按照微服务名来路由,它不影响配置文件中配置的路由)

可以将网关配置为基于向DiscoveryClient兼容服务注册表注册的服务来创建路由。

要实现这一点,请设置spring.cloud.gateway.discovery.locator.enabled=true,并确保DiscoveryClient实现(如Netflix Eureka, Consul, or Zookeeper)位于类路径中并已启用

为DiscoveryClient 路由配置断言和过滤器

默认情况下,网关为使用DiscoveryClient创建的路由定义了1个断言和过滤器

默认断言是用模式/serviceId/**定义的路径断言,其中serviceId是来自DiscoveryClient的服务的Id。

默认过滤器是一个重写路径过滤器,其正则为 /serviceId/?(?<remaining>.*)和替换/${remaining}。这将在请求发送到下游之前从路径中去除服务ID。

如果想定制DiscoveryClient路由使用的断言或过滤器, 设置 spring.cloud.gateway.discovery.locator.predicates[x] 和spring.cloud.gateway.discovery.locator.filters[y],这样做的时候,如果想保留这个功能,需要确保包含前面显示的默认断言和过滤器,比如:

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 + '/?(?<remaining>.*)'"
spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'"

十三、Reactor Netty访问日志

设置-Dreactor.netty.http.server.accessLogEnabled=true 打开Reactor Netty访问日志。 (它必须是Java系统属性,而不是Spring Boot属性。)

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

<appender name="accessLog" class="ch.qos.logback.core.FileAppender">
    <file>access_log.log</file>
    <encoder>
        <pattern>%msg%n</pattern>
    </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>

十四、CORS配置

可以配置网关来控制CORS行为。可以针对全局(即全部路由),也可以针对单个路由。

全局跨域配置

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "https://docs.spring.io"
            allowedMethods:
            - GET

在上面的示例中,对于所有GET requested路径,来自docs.spring.io的请求都允许CORS请求。

为了向不由某些网关路由断言处理的请求提供相同的CORS配置,请将spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping设置为true。当尝试支持CORS预检请求,但是由于HTTP方法为options,路由断言未设置为true时,这很有用。

路由跨域配置

可以针对单个路由,使用metadata.cors配置来应用cors跨域。如果这个路由中没有配置Path断言,那么会使用/**

spring:
  cloud:
    gateway:
      routes:
      - id: cors_route
        uri: https://example.org
        predicates:
        - Path=/service/**
        metadata:
          cors
            allowedOrigins: '*'
            allowedMethods:
              - GET
              - POST
            allowedHeaders: '*'
            maxAge: 30

十五、 Actuator API

/gateway actuator端点允许监控Spring Cloud Gateway应用程序并与之交互。要进行远程访问,必须在应用程序属性中启用并通过HTTP或JMX公开端点。

# 启用端点
management.endpoint.gateway.enabled=true # default value
management.endpoints.web.exposure.include=gateway

当开启后,并启动网关后,可以参照下面的路由去访问(试了下,发现只有部分路径能访问到结果,其它都404,比如能访问的有:

http://localhost:9091/actuator/gateway/globalfilters、

http://localhost:9091/actuator/gateway/routefilters、

http://localhost:9091/actuator/gateway/routes、

http://localhost:9091/actuator/gateway/routepredicates、

http://localhost:9091/actuator/gateway/refresh(post请求方式)、

http://localhost:9091/actuator/gateway/routes/{路由id})

[
   {
      "href":"/actuator/gateway/",
      "methods":[ "GET" ]
   },
   {
      "href":"/actuator/gateway/routedefinitions",
      "methods":[ "GET" ]
   },
   {
      "href":"/actuator/gateway/globalfilters",
      "methods":[ "GET" ]
   },
   {
      "href":"/actuator/gateway/routefilters",
      "methods":[ "GET" ]
   },
   {
      "href":"/actuator/gateway/routes",
      "methods":[ "POST", "GET" ]
   },
   {
      "href":"/actuator/gateway/routepredicates",
      "methods":[ "GET" ]
   },
   {
      "href":"/actuator/gateway/refresh",
      "methods":[ "POST" ]
   },
   {
      "href":"/actuator/gateway/routes/route-id-1/combinedfilters",
      "methods":[ "GET" ]
   },
   {
      "href":"/actuator/gateway/routes/route-id-1",
      "methods":[ "POST", "DELETE", "GET" ]
   }
]

1、Verbose Actuator 格式化

Spring Cloud Gateway增加了一种新的更详细的格式。它为每条路由添加了更多的细节,可以查看与每条路由相关联的谓词和过滤器,以及任何可用的配置。

// 配置/actuator/gateway/routes:
[
  {
    "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
  }
]
# 默认情况下,此功能处于启用状态。要禁用它,请设置以下属性(在未来的版本中,这将默认为true。)
spring.cloud.gateway.actuator.verbose.enabled=false

2、查找路由过滤器

Global Filters

要检索应用于所有路由的全局过滤器,请向 /actuator/gateway/globalfilters 发出GET请求。产生的响应类似于以下内容:

{
   
  "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
}

该响应包含已安装的全局过滤器的详细信息。对于每个全局过滤器,都有一个过滤器对象的字符串表示形式(例如,org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@77856cc5)和过滤器链中相应的顺序。

Route Filters

要检索应用于路由的GatewayFilter工厂,请向/actuator/gateway/routefilters发出GET请求。产生的响应类似于以下内容:

{
   
  "[AddRequestHeaderGatewayFilterFactory@570ed9c configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null,
  "[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]": null,
  "[SaveSessionGatewayFilterFactory@4449b273 configClass = Object]": null
}

响应包含应用于任何特定路由的GatewayFilter工厂的详细信息。对于每个工厂,都有一个相应对象的字符串表示(例如,[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object])。请注意,空值是由于端点控制器的不完整实现造成的,因为它试图设置筛选器链中对象的顺序,这不适用于GatewayFilter工厂对象。

3、刷新路由缓存

要清除路由缓存,请向/actuator/gateway/refresh发出POST请求。该请求返回一个没有响应正文的200。

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
}]

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

5、检索特定路由的信息

要检索有关单个路由的信息,请向/actuator/gateway/routes/{id}发出GET请求(例如/actuator/gateway/routes/first _ route)。产生的响应类似于以下内容:

{
   
  "id": "first_route",
  "predicates": [{
   
    "name": "Path",
    "args": {
   "_genkey_0":"/first"}
  }],
  "filters": [],
  "uri": "https://www.uri-destination.org",
  "order": 0
}

下表描述了响应的结构:

在这里插入图片描述

6、创建和删除特定的路由

要创建路由,请向/gateway/routes/{id_route_to_create}发出POST请求,并在JSON正文中指定路由的字段(请参见5、检索特定路由的信息)。

要删除路由,请向/gateway/routes/{id_route_to_delete}发出删除请求。

7、总结:所有端点的列表

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

在这里插入图片描述

8、在多个网关实例之间共享路由

Spring Cloud Gateway提供了两个RouteDefinitionRepository实现。

第一个是inmemorroutedefinitionrepository,它只存在于一个网关实例的内存中。这种类型的存储库不适合跨多个网关实例填充路由。

为了在Spring Cloud Gateway实例集群之间共享路由,可以使用RedisRouteDefinitionRepository。要启用这种类型的存储库,spring.cloud.gateway.redis-route-definition-repository.enabled必须设置为true,与RedisRateLimiter Filter Factory 类似,它需要使用spring-boot-starter-data-redis-reactive启动器。

十六、故障排查

1、日志级别

下列记录器可能包含有价值的DEBUG 和TRACE级别故障排除信息:

  • org.springframework.cloud.gateway
  • org.springframework.http.server.reactive
  • org.springframework.web.reactive
  • org.springframework.boot.autoconfigure.web
  • reactor.netty
  • redisratelimiter

2、窃听

Reactor Netty HttpClient和HttpServer可以启用窃听。当与将reactor.netty日志级别设置为DEBUG或TRACE结合使用时,它可以记录信息,例如通过网络发送和接收的头和主体。要启用窃听,请分别为httpserver和httpclient设置spring.cloud.gateway.httpserver.wiretap=true 和 spring.cloud.gateway.httpclient.wiretap=true。

十七、开发指南

1、编写自定义路由断言工厂

为了编写路由断言,需要将RoutePredicateFactory实现为一个bean。有一个名为AbstractRoutePredicateFactory的抽象类,可以对其进行扩展

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

}

2、编写自定义网关过滤器工厂

要编写GatewayFilter,必须将GatewayFilterFactory实现为bean。可以继承自名为AbstractGatewayFilterFactory的抽象类

(注意:pre是直接调用mutate来基于原来的请求修改属性)

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

}

(注意:post是在后面写then调用)

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

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

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

例如,要在配置文件中引用名为Something的过滤器,该过滤器一定是名为SomethingGatewayFilterFactory的类。

可以创建不带GatewayFilterFactory后缀的网关过滤器,如class AnotherThing。这个过滤器可以作为配置文件中的AnotherThing被引用。这不是受支持的命名约定,在未来的版本中可能会删除此语法。请更新过滤器名称以符合要求。(按照规范来命名GatewayFilterFactory过滤器,)

3、编写自定义全局过滤器

要编写自定义全局过滤器,必须将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();
}

十八、使用Spring MVC或Webflux构建一个简单的网关

Spring Cloud Gateway提供了一个名为ProxyExchange的对象。可以在常规的Spring web处理器中使用它作为方法参数。它通过镜像HTTP动词的方法支持基本的下游HTTP交换。对于MVC,它还支持通过forward()方法转发到本地处理程序。要使用ProxyExchange,请在类路径中包含正确的模块(spring-cloud-gateway-mvcspring-cloud-gateway-webflux)。

// 以下MVC示例将请求代理到 /test 下游的远程服务器:
@RestController
@SpringBootApplication
public class GatewaySampleApplication {
   

    @Value("${remote.home}")
    private URI home;

    @GetMapping("/test")
    public ResponseEntity<?> proxy(ProxyExchange<byte[]> proxy) throws Exception {
   
        return proxy.uri(home.toString() + "/image/png").get();
    }

}
//下面的例子对Webflux做了同样的事情:
@RestController
@SpringBootApplication
public class GatewaySampleApplication {
   

    @Value("${remote.home}")
    private URI home;

    @GetMapping("/test")
    public Mono<ResponseEntity<?>> proxy(ProxyExchange<byte[]> proxy) throws Exception {
   
        return proxy.uri(home.toString() + "/image/png").get();
    }

}
// ProxyExchange上的便利方法使处理程序方法能够发现和增强传入请求的URI路径。
// 例如,您可能希望提取路径的尾部元素,以便将它们传递到下游:
@GetMapping("/proxy/path/**")
public ResponseEntity<?> proxyPath(ProxyExchange<byte[]> proxy) throws Exception {
   
  String path = proxy.path("/proxy/path/");
  return proxy.uri(home.toString() + "/foos/" + path).get();
}

Spring MVC和Webflux的所有特性都可以用于网关处理程序方法。因此,例如,可以注入请求头和查询参数,并且可以用映射注释中的声明来约束传入的请求。

可以使用ProxyExchange上的header()方法向下游响应添加标头。

还可以通过向get()方法(以及其他方法)添加映射器来操作响应头(以及响应中您喜欢的任何内容)。映射器是一个函数,它获取传入的响应实体并将其转换为传出的响应实体。

为“敏感”头(默认为cookie和authorization)和“代理”(x-forwarded-*)头提供了一流的支持,前者不传递给下游。

十九、配置属性

查看所有Spring Cloud Gateway相关配置属性的列表(可以在application.properties文件内、application.yml文件内或作为命令行开关指定各种属性。下面提供了常见Spring Cloud Gateway属性的列表,以及对使用这些属性的底层类的引用。)(属性贡献可以来自类路径上的其他jar文件,因此这不是一个详尽的列表。此外,还可以定义自己的属性。)

NameDefaultDescription
spring.cloud.gateway.default-filtersList of filter definitions that are applied to every route.
spring.cloud.gateway.discovery.locator.enabledfalseFlag that enables DiscoveryClient gateway integration.
spring.cloud.gateway.discovery.locator.filters
spring.cloud.gateway.discovery.locator.include-expressiontrueSpEL expression that will evaluate whether to include a service in gateway integration or not, defaults to: true.
spring.cloud.gateway.discovery.locator.lower-case-service-idfalseOption to lower case serviceId in predicates and filters, defaults to false. Useful with eureka when it automatically uppercases serviceId. so MYSERIVCE, would match /myservice/**
spring.cloud.gateway.discovery.locator.predicates
spring.cloud.gateway.discovery.locator.route-id-prefixThe prefix for the routeId, defaults to discoveryClient.getClass().getSimpleName() + “_”. Service Id will be appended to create the routeId.
spring.cloud.gateway.discovery.locator.url-expression'lb://'+serviceIdSpEL expression that create the uri for each route, defaults to: ‘lb://’+serviceId.
spring.cloud.gateway.enabledtrueEnables gateway functionality.
spring.cloud.gateway.fail-on-route-definition-errortrueOption to fail on route definition errors, defaults to true. Otherwise, a warning is logged.
spring.cloud.gateway.filter.add-request-header.enabledtrueEnables the add-request-header filter.
spring.cloud.gateway.filter.add-request-parameter.enabledtrueEnables the add-request-parameter filter.
spring.cloud.gateway.filter.add-response-header.enabledtrueEnables the add-response-header filter.
spring.cloud.gateway.filter.circuit-breaker.enabledtrueEnables the circuit-breaker filter.
spring.cloud.gateway.filter.dedupe-response-header.enabledtrueEnables the dedupe-response-header filter.
spring.cloud.gateway.filter.fallback-headers.enabledtrueEnables the fallback-headers filter.
spring.cloud.gateway.filter.hystrix.enabledtrueEnables the hystrix filter.
spring.cloud.gateway.filter.json-to-grpc.enabledtrueEnables the JSON to gRPC filter.
spring.cloud.gateway.filter.local-response-cache.enabledfalseEnables the local-response-cache filter.
spring.cloud.gateway.filter.local-response-cache.request.no-cache-strategy
spring.cloud.gateway.filter.local-response-cache.sizeMaximum size of the cache to evict entries for this route (in KB, MB and GB).
spring.cloud.gateway.filter.local-response-cache.time-to-live5mTime to expire a cache entry (expressed in s for seconds, m for minutes, and h for hours).
spring.cloud.gateway.filter.map-request-header.enabledtrueEnables the map-request-header filter.
spring.cloud.gateway.filter.modify-request-body.enabledtrueEnables the modify-request-body filter.
spring.cloud.gateway.filter.modify-response-body.enabledtrueEnables the modify-response-body filter.
spring.cloud.gateway.filter.prefix-path.enabledtrueEnables the prefix-path filter.
spring.cloud.gateway.filter.preserve-host-header.enabledtrueEnables the preserve-host-header filter.
spring.cloud.gateway.filter.redirect-to.enabledtrueEnables the redirect-to filter.
spring.cloud.gateway.filter.remove-hop-by-hop.headers
spring.cloud.gateway.filter.remove-hop-by-hop.order0
spring.cloud.gateway.filter.remove-request-header.enabledtrueEnables the remove-request-header filter.
spring.cloud.gateway.filter.remove-request-parameter.enabledtrueEnables the remove-request-parameter filter.
spring.cloud.gateway.filter.remove-response-header.enabledtrueEnables the remove-response-header filter.
spring.cloud.gateway.filter.request-header-size.enabledtrueEnables the request-header-size filter.
spring.cloud.gateway.filter.request-header-to-request-uri.enabledtrueEnables the request-header-to-request-uri filter.
spring.cloud.gateway.filter.request-rate-limiter.default-key-resolver
spring.cloud.gateway.filter.request-rate-limiter.default-rate-limiter
spring.cloud.gateway.filter.request-rate-limiter.enabledtrueEnables the request-rate-limiter filter.
spring.cloud.gateway.filter.request-size.enabledtrueEnables the request-size filter.
spring.cloud.gateway.filter.retry.enabledtrueEnables the retry filter.
spring.cloud.gateway.filter.rewrite-location-response-header.enabledtrueEnables the rewrite-location-response-header filter.
spring.cloud.gateway.filter.rewrite-location.enabledtrueEnables the rewrite-location filter.
spring.cloud.gateway.filter.rewrite-path.enabledtrueEnables the rewrite-path filter.
spring.cloud.gateway.filter.rewrite-request-parameter.enabledtrueEnables the rewrite-request-parameter filter.
spring.cloud.gateway.filter.rewrite-response-header.enabledtrueEnables the rewrite-response-header filter.
spring.cloud.gateway.filter.save-session.enabledtrueEnables the save-session filter.
spring.cloud.gateway.filter.secure-headers.content-security-policydefault-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'
spring.cloud.gateway.filter.secure-headers.content-type-optionsnosniff
spring.cloud.gateway.filter.secure-headers.disable
spring.cloud.gateway.filter.secure-headers.download-optionsnoopen
spring.cloud.gateway.filter.secure-headers.enabledtrueEnables the secure-headers filter.
spring.cloud.gateway.filter.secure-headers.frame-optionsDENY
spring.cloud.gateway.filter.secure-headers.permitted-cross-domain-policiesnone
spring.cloud.gateway.filter.secure-headers.referrer-policyno-referrer
spring.cloud.gateway.filter.secure-headers.strict-transport-securitymax-age=631138519
spring.cloud.gateway.filter.secure-headers.xss-protection-header1 ; mode=block
spring.cloud.gateway.filter.set-path.enabledtrueEnables the set-path filter.
spring.cloud.gateway.filter.set-request-header.enabledtrueEnables the set-request-header filter.
spring.cloud.gateway.filter.set-request-host-header.enabledtrueEnables the set-request-host-header filter.
spring.cloud.gateway.filter.set-response-header.enabledtrueEnables the set-response-header filter.
spring.cloud.gateway.filter.set-status.enabledtrueEnables the set-status filter.
spring.cloud.gateway.filter.strip-prefix.enabledtrueEnables the strip-prefix filter.
spring.cloud.gateway.forwarded.enabledtrueEnables the ForwardedHeadersFilter.
spring.cloud.gateway.global-filter.adapt-cached-body.enabledtrueEnables the adapt-cached-body global filter.
spring.cloud.gateway.global-filter.forward-path.enabledtrueEnables the forward-path global filter.
spring.cloud.gateway.global-filter.forward-routing.enabledtrueEnables the forward-routing global filter.
spring.cloud.gateway.global-filter.load-balancer-client.enabledtrueEnables the load-balancer-client global filter.
spring.cloud.gateway.global-filter.local-response-cache.enabledtrueEnables the local-response-cache filter for all routes, it allows to add a specific configuration at route level using LocalResponseCache filter.
spring.cloud.gateway.global-filter.netty-routing.enabledtrueEnables the netty-routing global filter.
spring.cloud.gateway.global-filter.netty-write-response.enabledtrueEnables the netty-write-response global filter.
spring.cloud.gateway.global-filter.reactive-load-balancer-client.enabledtrueEnables the reactive-load-balancer-client global filter.
spring.cloud.gateway.global-filter.remove-cached-body.enabledtrueEnables the remove-cached-body global filter.
spring.cloud.gateway.global-filter.route-to-request-url.enabledtrueEnables the route-to-request-url global filter.
spring.cloud.gateway.global-filter.websocket-routing.enabledtrueEnables the websocket-routing global filter.
spring.cloud.gateway.globalcors.add-to-simple-url-handler-mappingfalseIf global CORS config should be added to the URL handler.
spring.cloud.gateway.globalcors.cors-configurations
spring.cloud.gateway.handler-mapping.order1The order of RoutePredicateHandlerMapping.
spring.cloud.gateway.httpclient.compressionfalseEnables compression for Netty HttpClient.
spring.cloud.gateway.httpclient.connect-timeoutThe connect timeout in millis, the default is 30s.
spring.cloud.gateway.httpclient.max-header-sizeThe max response header size.
spring.cloud.gateway.httpclient.max-initial-line-lengthThe max initial line length.
spring.cloud.gateway.httpclient.pool.acquire-timeoutOnly for type FIXED, the maximum time in millis to wait for acquiring.
spring.cloud.gateway.httpclient.pool.eviction-interval0Perform regular eviction checks in the background at a specified interval. Disabled by default ({@link Duration#ZERO})
spring.cloud.gateway.httpclient.pool.max-connectionsOnly for type FIXED, the maximum number of connections before starting pending acquisition on existing ones.
spring.cloud.gateway.httpclient.pool.max-idle-timeTime in millis after which the channel will be closed. If NULL, there is no max idle time.
spring.cloud.gateway.httpclient.pool.max-life-timeDuration after which the channel will be closed. If NULL, there is no max life time.
spring.cloud.gateway.httpclient.pool.metricsfalseEnables channel pools metrics to be collected and registered in Micrometer. Disabled by default.
spring.cloud.gateway.httpclient.pool.nameproxyThe channel pool map name, defaults to proxy.
spring.cloud.gateway.httpclient.pool.typeType of pool for HttpClient to use, defaults to ELASTIC.
spring.cloud.gateway.httpclient.proxy.hostHostname for proxy configuration of Netty HttpClient.
spring.cloud.gateway.httpclient.proxy.non-proxy-hosts-patternRegular expression (Java) for a configured list of hosts. that should be reached directly, bypassing the proxy
spring.cloud.gateway.httpclient.proxy.passwordPassword for proxy configuration of Netty HttpClient.
spring.cloud.gateway.httpclient.proxy.portPort for proxy configuration of Netty HttpClient.
spring.cloud.gateway.httpclient.proxy.typeproxyType for proxy configuration of Netty HttpClient.
spring.cloud.gateway.httpclient.proxy.usernameUsername for proxy configuration of Netty HttpClient.
spring.cloud.gateway.httpclient.response-timeoutThe response timeout.
spring.cloud.gateway.httpclient.ssl.close-notify-flush-timeout3000msSSL close_notify flush timeout. Default to 3000 ms.
spring.cloud.gateway.httpclient.ssl.close-notify-read-timeout0SSL close_notify read timeout. Default to 0 ms.
spring.cloud.gateway.httpclient.ssl.handshake-timeout10000msSSL handshake timeout. Default to 10000 ms
spring.cloud.gateway.httpclient.ssl.key-passwordKey password, default is same as keyStorePassword.
spring.cloud.gateway.httpclient.ssl.key-storeKeystore path for Netty HttpClient.
spring.cloud.gateway.httpclient.ssl.key-store-passwordKeystore password.
spring.cloud.gateway.httpclient.ssl.key-store-providerKeystore provider for Netty HttpClient, optional field.
spring.cloud.gateway.httpclient.ssl.key-store-typeJKSKeystore type for Netty HttpClient, default is JKS.
spring.cloud.gateway.httpclient.ssl.trusted-x509-certificatesTrusted certificates for verifying the remote endpoint’s certificate.
spring.cloud.gateway.httpclient.ssl.use-insecure-trust-managerfalseInstalls the netty InsecureTrustManagerFactory. This is insecure and not suitable for production.
spring.cloud.gateway.httpclient.websocket.max-frame-payload-lengthMax frame payload length.
spring.cloud.gateway.httpclient.websocket.proxy-pingtrueProxy ping frames to downstream services, defaults to true.
spring.cloud.gateway.httpclient.wiretapfalseEnables wiretap debugging for Netty HttpClient.
spring.cloud.gateway.httpserver.wiretapfalseEnables wiretap debugging for Netty HttpServer.
spring.cloud.gateway.loadbalancer.use404false
spring.cloud.gateway.metrics.enabledfalseEnables the collection of metrics data.
spring.cloud.gateway.metrics.prefixspring.cloud.gatewayThe prefix of all metrics emitted by gateway.
spring.cloud.gateway.metrics.tagsTags map that added to metrics.
spring.cloud.gateway.observability.enabledtrueIf Micrometer Observability support should be turned on.
spring.cloud.gateway.predicate.after.enabledtrueEnables the after predicate.
spring.cloud.gateway.predicate.before.enabledtrueEnables the before predicate.
spring.cloud.gateway.predicate.between.enabledtrueEnables the between predicate.
spring.cloud.gateway.predicate.cloud-foundry-route-service.enabledtrueEnables the cloud-foundry-route-service predicate.
spring.cloud.gateway.predicate.cookie.enabledtrueEnables the cookie predicate.
spring.cloud.gateway.predicate.header.enabledtrueEnables the header predicate.
spring.cloud.gateway.predicate.host.enabledtrueEnables the host predicate.
spring.cloud.gateway.predicate.method.enabledtrueEnables the method predicate.
spring.cloud.gateway.predicate.path.enabledtrueEnables the path predicate.
spring.cloud.gateway.predicate.query.enabledtrueEnables the query predicate.
spring.cloud.gateway.predicate.read-body.enabledtrueEnables the read-body predicate.
spring.cloud.gateway.predicate.remote-addr.enabledtrueEnables the remote-addr predicate.
spring.cloud.gateway.predicate.weight.enabledtrueEnables the weight predicate.
spring.cloud.gateway.predicate.xforwarded-remote-addr.enabledtrueEnables the xforwarded-remote-addr predicate.
spring.cloud.gateway.redis-rate-limiter.burst-capacity-headerX-RateLimit-Burst-CapacityThe name of the header that returns the burst capacity configuration.
spring.cloud.gateway.redis-rate-limiter.config
spring.cloud.gateway.redis-rate-limiter.include-headerstrueWhether or not to include headers containing rate limiter information, defaults to true.
spring.cloud.gateway.redis-rate-limiter.remaining-headerX-RateLimit-RemainingThe name of the header that returns number of remaining requests during the current second.
spring.cloud.gateway.redis-rate-limiter.replenish-rate-headerX-RateLimit-Replenish-RateThe name of the header that returns the replenish rate configuration.
spring.cloud.gateway.redis-rate-limiter.requested-tokens-headerX-RateLimit-Requested-TokensThe name of the header that returns the requested tokens configuration.
spring.cloud.gateway.restrictive-property-accessor.enabledtrueRestricts method and property access in SpEL.
spring.cloud.gateway.routesList of Routes.
spring.cloud.gateway.set-status.original-status-header-nameThe name of the header which contains http code of the proxied request.
spring.cloud.gateway.streaming-media-types
spring.cloud.gateway.x-forwarded.enabledtrueIf the XForwardedHeadersFilter is enabled.
spring.cloud.gateway.x-forwarded.for-appendtrueIf appending X-Forwarded-For as a list is enabled.
spring.cloud.gateway.x-forwarded.for-enabledtrueIf X-Forwarded-For is enabled.
spring.cloud.gateway.x-forwarded.host-appendtrueIf appending X-Forwarded-Host as a list is enabled.
spring.cloud.gateway.x-forwarded.host-enabledtrueIf X-Forwarded-Host is enabled.
spring.cloud.gateway.x-forwarded.order0The order of the XForwardedHeadersFilter.
spring.cloud.gateway.x-forwarded.port-appendtrueIf appending X-Forwarded-Port as a list is enabled.
spring.cloud.gateway.x-forwarded.port-enabledtrueIf X-Forwarded-Port is enabled.
spring.cloud.gateway.x-forwarded.prefix-appendtrueIf appending X-Forwarded-Prefix as a list is enabled.
spring.cloud.gateway.x-forwarded.prefix-enabledtrueIf X-Forwarded-Prefix is enabled.
spring.cloud.gateway.x-forwarded.proto-appendtrueIf appending X-Forwarded-Proto as a list is enabled.
spring.cloud.gateway.x-forwarded.proto-enabledtrueIf X-Forwarded-Proto is enabled.

二十、搭建网关

在这里插入图片描述

二十一、搭建网关

在了解了上述网关的使用方法后,我们动手搭建1个网关

网关服务

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.9.RELEASE</version>
        <relativePath/>
    </parent>

    <groupId>com.zzhua</groupId>
    <artifactId>cloud-learn</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
        <alibaba.version>2.2.5.RELEASE</alibaba.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>


    </dependencies>

    <dependencyManagement>

        <dependencies>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- springCloud -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

        </dependencies>


    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
application.yml
server:
  port: 9091
spring:
  application:
    name: my-gateway
  cloud:
    nacos:
      server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          #(开启服务注册发现添加到网关路由功能)
          # 测试访问: http://localhost:8084/orderService/createOrder 能通;(order-service)
          # 现在访问: http://localhost:9091/order-service/orderService/createOrder 能通
          enabled: true
      routes:
        # 测试访问: http://localhost:8081/test/test01 能通;(netty-chat-web)
        # 现在访问: http://localhost:9091/test/test01 能通;
        - id: http-8081
          uri: http://localhost:8081
          filters:
            - AddResponseHeader=X-Response-Red, Blue
          predicates:
            - Path=/test/**
        # 测试访问: ws://localhost:9090/ws?chatKey=1 能通;(netty-chat-web)
        # 现在访问: ws://localhost:9091/ws?chatKey=1 能通;
        - id: ws-9090
          uri: ws://localhost:9090
          predicates:
            - Path=/ws/**
        # 测试访问: http://localhost:8084/orderService/createOrder 能通;(order-service)
        # 现在访问: http://localhost:9091/order/orderService/createOrder 能通;
        - id: http-9090
          uri: lb://order-service
          filters:
            - StripPrefix=1
          predicates:
            - Path=/order/**
        # 测试访问: http://localhost:8084/orderService/createOrder 能通;(order-service)
        # 现在访问: http://localhost:9091/order/orderService/createOrder 能通;
        # 这里测试自定义网关过滤器->AddFixedHeaderGatewayFilterFactory
        - id: http-9090-2
          uri: lb://order-service
          filters:
            - StripPrefix=1
            - name: AddFixedHeader
              args:
                headerName: token
                headerValue: ey1234
          predicates:
            - Path=/order2/**
management:
  endpoint:
    gateway:
      enabled: true
  endpoints:
    web:
      exposure:
        include: gateway
GateWayApp
@SpringBootApplication
public class GateWayApp {

    public static void main(String[] args) {
        SpringApplication.run(GateWayApp.class, args);
    }

}
LoggingGlobalFilter
/* 自定义全局过滤器 */
@Slf4j
@Component
public class LoggingGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        URI uri = exchange.getRequest().getURI();
        log.info("LoggingGlobalFilter-处理请求...{}", uri.toString());

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;
    }
}
AddFixedHeaderGatewayFilterFactory
/* 自定义网关过滤器 */
@Component
public class AddFixedHeaderGatewayFilterFactory extends AbstractGatewayFilterFactory<AddFixedHeaderGatewayFilterFactory.Config> {

    public AddFixedHeaderGatewayFilterFactory() {

        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        
        // 在被调用服务中打上断点, 发现确实添加了指定的请求头
        return (exchange, chain) -> {
            
            ServerHttpRequest req = exchange.getRequest().mutate()
                .header(config.headerName, config.headerValue).build();
            
            return chain.filter(exchange.mutate().request(req).build());
        };

    }

    @Data
    static class Config {

        private String headerName;

        private String headerValue;

    }
}
CustomGatewayConfig
@Configuration
public class CustomGatewayConfig {

    // 静态引入 GatewayFilters 和RoutePredicates
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder
                .routes()
                .route("order-api",
                        // Java Route Api配置路由, 与配置文件中写法功能相同
                        // 测试访问: http://localhost:8084/orderService/createOrder 能通
                        // 现在访问: http://localhost:9091/order-api/orderService/createOrder 能通
                        r -> r.path("/order-api/**")
                              .filters(f -> {
                                  // 这里仅启动的时候, 会调用这里
                                  GatewayFilterSpec gatewayFilterSpec = f
                                      .addResponseHeader("x-api", "order-api");
                                  gatewayFilterSpec.stripPrefix(1);
                                  return gatewayFilterSpec;
                              })
                              .uri("lb://order-service")
                 )
                .route("order-api2",
                        // 测试访问: http://localhost:8084/orderService/createOrder 能通
                        // 现在访问: http://localhost:9091/order-api2/orderService/createOrder 能通
                        r -> r.path("/order-api2/**")
                              .filters(f -> f.stripPrefix(1)
                                       .addResponseHeader("x-api2", "order-api2")
                              )
                              .uri("http://localhost:8084")
                )
                .build();
    }

}

order-service

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.9.RELEASE</version>
        <relativePath/>
    </parent>

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zzhua</groupId>
    <artifactId>order-service</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
        <alibaba.version>2.2.5.RELEASE</alibaba.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>


    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- springCloud -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
application.yml
server:
  port: 8084
  servlet:
    context-path: /orderService
spring:
  application:
    name: order-service
  cloud:
    nacos:
      server-addr: localhost:8848
OrderApp
@SpringBootApplication
public class OrderApp {
    public static void main(String[] args) {
        SpringApplication.run(OrderApp.class, args);
    }
}
OrderController
@RestController
public class OrderController {

    @GetMapping("/createOrder")
    public Object createOrder() {
        return "order: 1";
    }

}

测试

先启动nacos,再启动order-service,在启动netty-chat-web,最后启动网关服务,经测试上述都能正常工作。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐