• Spring Cloud Gateway官方文档学习


    文章目录

    推荐

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

    spring cloud gateway官方文档介绍

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

    写在前面

    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配置

    
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-gatewayartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-actuatorartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    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
    • 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
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    路由断言的两种写法

    1、简短断言

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

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

    三、路由断言工厂

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

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

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

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

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

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

    该断言提取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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

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

    如果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");
    
    • 1
    • 2
    • 3

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

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    修改远程地址的解析方式

    默认情况下,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
    
    • 1

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

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

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

    四、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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    (如下:使用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}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2、AddRequestParameter 网关过滤工厂

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

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

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    spring:
      cloud:
        gateway:
          routes:
          - id: add_response_header_route
            uri: https://example.org
            predicates:
            - Host: {segment}.myhost.org
            filters:
            # 也可以使用url中的参数
            - AddResponseHeader=foo, bar-{segment}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

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

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

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    // 使用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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    主要场景是使用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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在请求被转发到回退的情况下,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"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    // 使用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
    • 9
    • 10

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

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

    • 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: 请求头添加到下游请求中,其中包含来自传入HTTP请求的Blue请求头的值。
            - MapRequestHeader=Blue, X-Request-Red
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    8、PrefixPath 网关过滤工厂

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

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

    9、PreserveHostHeader 网关过滤工厂

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

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

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    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}
    
    • 1
    • 2
    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 # 一个请求花费多少令牌
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    // 使用java配置一个KeyResolver KeyResolver是一个简单的工具,它获取用户请求参数(注意,不建议在生产中使用)。
    @Bean
    KeyResolver userKeyResolver() {
       
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    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}"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

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

    12、RemoveRequestHeader 网关过滤工厂

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

    spring:
      cloud:
        gateway:
          routes:
          - id: removerequestheader_route
            uri: https://example.org
            filters:
            # 网下游发请求时,删除X-Request-Foo 请求头
            - RemoveRequestHeader=X-Request-Foo
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    13、RemoveResponseHeader 网关过滤工厂

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

    spring:
      cloud:
        gateway:
          routes:
          - id: removeresponseheader_route
            uri: https://example.org
            filters:
            # 在响应返回前 删除X-Response-Foo请求头。
            - RemoveResponseHeader=X-Response-Foo
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注意:要删除任何类型的敏感请求头,应该为想要删除的任何路由配置此过滤器。 此外,您可以使用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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

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

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

    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, ,
    
    • 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仅当原始请求路径不包含版本时,才剥离版本。
    • 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=***
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    19、SaveSession 网关过滤工厂

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

    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安全性与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
    
    • 1
    • 2

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

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    spring:
      cloud:
        gateway:
          routes:
          - id: setrequestheader_route
            uri: https://example.org
            predicates:
            - Host: {segment}.myhost.org
            filters:
            # 也可以使用path路径上的参数
            - SetRequestHeader=foo, bar-{segment}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    spring:
      cloud:
        gateway:
          routes:
          - id: setresponseheader_route
            uri: https://example.org
            predicates:
            - Host: {segment}.myhost.org
            filters:
            # 也可以使用path路径上的参数
            - SetResponseHeader=foo, bar-{segment}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    # 可以将SetStatus GatewayFilter配置为在响应的标头中返回代理请求的原始HTTP状态代码。如果使用以下属性进行配置,标头将被添加到响应中:
    spring:
      cloud:
        gateway:
          set-status:
            original-status-header-name: original-http-status
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

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

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

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

    如果没有在路由定义中作为过滤器参数提供,则默认请求大小被设置为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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    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;
        }
    }
    
    • 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
    • 28
    • 29

    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;
        }
    }
    
    • 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
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

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

    或者使用yml配置

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

    它是如何工作的?

    {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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    # 进行缓存
    spring:
      cloud:
        gateway:
          routes:
          - id: cache_request_body_route
            uri: lb://downstream   # lb://开头表示从注册中心拉取服务, 并且负载均衡
            predicates:
            - Path=/downstream/**
            filters:
            - name: CacheRequestBody
              args:
                bodyClass: java.lang.String
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

    当通过网关向/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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    34、Default过滤器

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

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

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

    五、GlobalFilter-全局过滤器

    GlobalFilter接口与GatewayFilter具有相同的方法签名(方法签名都是:Mono 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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    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/**
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    默认情况下,当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/**
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

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

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

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

    如果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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    八、配置-Configuration

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

    // RouteDefinitionLocator接口的定义
    public interface RouteDefinitionLocator {
       
        Flux<RouteDefinition> getRouteDefinitions();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    默认情况下,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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    对于网关的某些用途,属性是足够的,但是某些生产用例从外部源(如数据库)加载配置。未来的里程碑版本将会有基于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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    // 可以从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
    • 6
    • 7
    • 8

    十、Http超时配置

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

    1、全局超时设置

    要配置全局http超时:

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

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    // 使用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();
          }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    # 注意:当单个路由设置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
    • 9

    十一、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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    这种风格还允许更多的自定义断言。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}。这将在请求发送到下游之前从路径中去除服务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 + '/?(?.*)'"
    spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    十三、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.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行为。可以针对全局(即全部路由),也可以针对单个路由。

    全局跨域配置

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

    在上面的示例中,对于所有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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    十五、 Actuator API

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

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

    当开启后,并启动网关后,可以参照下面的路由去访问(试了下,发现只有部分路径能访问到结果,其它都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
    • 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
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    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
      }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    # 默认情况下,此功能处于启用状态。要禁用它,请设置以下属性(在未来的版本中,这将默认为true。)
    spring.cloud.gateway.actuator.verbose.enabled=false
    
    • 1
    • 2

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

    该响应包含已安装的全局过滤器的详细信息。对于每个全局过滤器,都有一个过滤器对象的字符串表示形式(例如,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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    响应包含应用于任何特定路由的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
    }]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

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

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

    下表描述了响应的结构:

    在这里插入图片描述

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

    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
        }
    
    }
    
    • 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
    • 28
    • 29
    • 30

    (注意: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
        }
    
    }
    
    • 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
    • 28
    • 29
    在配置中命名自定义过滤器和引用

    自定义过滤器类名应以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();
    }
    
    • 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

    十八、使用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();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    //下面的例子对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();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    // 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    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
    
    <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.0modelVersion>
    
        <parent>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-parentartifactId>
            <version>2.3.9.RELEASEversion>
            <relativePath/>
        parent>
    
        <groupId>com.zzhuagroupId>
        <artifactId>cloud-learnartifactId>
        <version>1.0-SNAPSHOTversion>
    
        <properties>
            <spring-cloud.version>Hoxton.SR8spring-cloud.version>
            <alibaba.version>2.2.5.RELEASEalibaba.version>
            <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
            <java.version>1.8java.version>
        properties>
    
        <dependencies>
    
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-gatewayartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-loadbalancerartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-data-redis-reactiveartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-actuatorartifactId>
            dependency>
    
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
            dependency>
    
    
        dependencies>
    
        <dependencyManagement>
    
            <dependencies>
    
                <dependency>
                    <groupId>com.alibaba.cloudgroupId>
                    <artifactId>spring-cloud-alibaba-dependenciesartifactId>
                    <version>${alibaba.version}version>
                    <type>pomtype>
                    <scope>importscope>
                dependency>
    
                
                <dependency>
                    <groupId>org.springframework.cloudgroupId>
                    <artifactId>spring-cloud-dependenciesartifactId>
                    <version>${spring-cloud.version}version>
                    <type>pomtype>
                    <scope>importscope>
                dependency>
    
            dependencies>
    
    
        dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-maven-pluginartifactId>
                plugin>
            plugins>
        build>
    
    project>
    
    • 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
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    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
    
    • 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
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    GateWayApp
    @SpringBootApplication
    public class GateWayApp {
    
        public static void main(String[] args) {
            SpringApplication.run(GateWayApp.class, args);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    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;
    
        }
    }
    
    • 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
    • 28
    • 29
    • 30
    • 31
    • 32
    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();
        }
    
    }
    
    • 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
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    order-service

    pom.xml
    
    <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.bootgroupId>
            <artifactId>spring-boot-starter-parentartifactId>
            <version>2.3.9.RELEASEversion>
            <relativePath/>
        parent>
    
        <modelVersion>4.0.0modelVersion>
    
        <groupId>com.zzhuagroupId>
        <artifactId>order-serviceartifactId>
        <version>1.0-SNAPSHOTversion>
    
        <properties>
            <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
            <java.version>1.8java.version>
            <spring-cloud.version>Hoxton.SR8spring-cloud.version>
            <alibaba.version>2.2.5.RELEASEalibaba.version>
        properties>
    
        <dependencies>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
    
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
            dependency>
    
    
        dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>com.alibaba.cloudgroupId>
                    <artifactId>spring-cloud-alibaba-dependenciesartifactId>
                    <version>${alibaba.version}version>
                    <type>pomtype>
                    <scope>importscope>
                dependency>
                
                <dependency>
                    <groupId>org.springframework.cloudgroupId>
                    <artifactId>spring-cloud-dependenciesartifactId>
                    <version>${spring-cloud.version}version>
                    <type>pomtype>
                    <scope>importscope>
                dependency>
            dependencies>
        dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-maven-pluginartifactId>
                plugin>
            plugins>
        build>
    
    project>
    
    • 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
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    application.yml
    server:
      port: 8084
      servlet:
        context-path: /orderService
    spring:
      application:
        name: order-service
      cloud:
        nacos:
          server-addr: localhost:8848
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    OrderApp
    @SpringBootApplication
    public class OrderApp {
        public static void main(String[] args) {
            SpringApplication.run(OrderApp.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    OrderController
    @RestController
    public class OrderController {
    
        @GetMapping("/createOrder")
        public Object createOrder() {
            return "order: 1";
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    测试

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

  • 相关阅读:
    PowerShell系列(十二):PowerShell Cmdlet高级参数介绍(二)
    ElasticSearch之ES8新特性及集群安装
    spark
    微信小程序毕业设计题目学生公寓生活管理系统+后台管理系统|前后分离VUE.js
    数组(C语言)(详细过程!!!)
    es6-promise对象详解
    C#A类调用B类的方法,在方法中更新B类的控件
    野心勃勃的日本第五代计算机,是如何一步步走向失败的
    蓝桥杯刷题(二)
    Java相关的序列化与反序列化
  • 原文地址:https://blog.csdn.net/qq_16992475/article/details/136272527