一篇文章搞定spring gateway

1. 什么是Spring Cloud Gateway

Spring Cloud Gateway是Spring Cloud生态系统中的一个组件,用于构建基于Spring Boot的微服务架构中的网关服务。网关是系统的入口点,它负责接收所有外部请求,并根据一定的规则将请求路由到相应的微服务。以下是Spring Cloud Gateway的主要特性和用途:

特性

  1. 动态路由: Spring Cloud Gateway支持动态路由,这意味着可以在运行时动态地添加、修改或删除路由规则。这为系统的灵活性和可维护性提供了便利。
  2. 谓词和过滤器: 路由规则由谓词和过滤器组成。谓词用于匹配请求的条件,而过滤器用于在请求被路由前或路由后执行一些操作,如修改请求、响应、添加请求头等。
  3. 集成性: Spring Cloud Gateway可以与Spring Cloud生态系统中的其他组件(如服务注册中心、配置中心、Security等)无缝集成,为微服务架构提供全面的支持。
  4. 熔断和限流: Spring Cloud Gateway集成了熔断器和限流器,可以有效地保护微服务免受过载和故障的影响。熔断器用于处理故障,限流器用于控制请求的速率。
  5. 动态刷新: Spring Cloud Gateway支持动态刷新配置,使得可以在运行时动态修改配置,而无需重新启动网关服务。
  6. WebSocket支持: Spring Cloud Gateway对WebSocket提供了支持,可以轻松地处理WebSocket流量并进行路由。
  7. 统一的入口点: 通过网关,可以实现对微服务架构的统一入口点管理,从而简化了系统的管理和维护。

用途

  1. 路由: Spring Cloud Gateway充当系统的请求入口,根据路由规则将请求转发到相应的微服务。这有助于实现统一的请求处理和路由策略。
  2. 过滤: 可以使用过滤器执行各种任务,如身份验证、日志记录、请求修改等。这使得可以在网关层面处理与请求和响应相关的横切关注点。
  3. 熔断和限流: 通过集成熔断器和限流器,可以提高系统的稳定性,防止微服务由于过载或故障而崩溃。
  4. 统一管理: 通过集成Spring Cloud生态系统的其他组件,可以实现微服务架构的全面管理,包括服务注册、配置管理、安全性等。
  5. 动态配置: 可以动态地添加、修改或删除路由规则,而无需重新启动网关服务,从而提高系统的灵活性。

总体而言,Spring Cloud Gateway是构建现代化、分布式应用程序的重要工具,通过提供灵活的路由和过滤机制,有助于简化微服务架构的管理和维护。它为开发人员提供了一种强大而灵活的方式,以满足不同应用场景的需求。

官网文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories

核心概念

  • 路由(route)

路由是网关中最基础的部分,路由信息包括一个ID、一个目的URI、一组断言工厂、一组Filter组成。如果断言为真,则说明请求的URL和配置的路由匹配。

  • 断言(predicates)

Java8中的断言函数,SpringCloud Gateway中的断言函数类型是Spring5.0框架中的ServerWebExchange。断言函数允许开发者去定义匹配Http request中的任何信息,比如请求头和参数等。

  • 过滤器(Filter)

SpringCloud Gateway中的filter分为Gateway FilIer和Global Filter。Filter可以对请求和响应进行处理。

工作原理

Spring Cloud Gateway 的工作原理跟 Zuul 的差不多,最大的区别就是 Gateway 的 Filter 只有 pre 和 post 两种。

image.png
  • 客户端向 Spring Cloud Gateway 发出请求,如果请求与网关程序定义的路由匹配,则该请求就会被发送到网关 Web 处理程序,此时处理程序运行特定的请求过滤器链。
  • 过滤器之间用虚线分开的原因是过滤器可能会在发送代理请求的前后执行逻辑。所有 pre 过滤器逻辑先执行,然后执行代理请求;代理请求完成后,执行 post 过滤器逻辑。

2. Spring Cloud Gateway快速开始

1) 引入依赖

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

<!-- nacos服务注册与发现(当然这不是必须的) -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

注意:会和spring-webmvc的依赖冲突,需要排除spring-webmvc
2) 编写yml配置文件

server:
  port: 8888
spring:
  application:
    name: mall-gateway
  #配置nacos注册中心地址
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

    gateway:
      discovery:
        locator:
          # 默认为false,设为true开启通过微服务创建路由的功能,即可以通过微服务名访问服务
          # http://localhost:8888/mall-order/order/findOrderByUserId/1
          enabled: true
      # 是否开启网关    
      enabled: true 

3)测试

image.png

3. 路由主要有四个配置

  • 路由id(id):id用于唯一标识一个路由规则,可以通过该标识符进行管理和操作。
  • 路由目标(uri):uri指定了该路由规则要将请求转发到的目标服务的基本URI。这可以是一个外部服务的URL,也可以是注册在服务注册中心的服务名。
  • 路由断言(predicates):predicates定义了路由规则的匹配条件,即何种情况下该路由规则应该生效。谓词通常包括路径、方法、请求头等条件。
  • 路由过滤器(filters):filters定义了路由规则应用的过滤器,过滤器在请求被路由前或路由后执行一些操作,如修改请求、修改响应、添加请求头等。

Predicates 和 Filters 是构建路由规则的基本元素。Predicates 用于匹配请求的条件,而 Filters 用于对请求和响应进行处理。它们是通过链式调用的方式组成的过滤器链。

3.断言工厂(Route Predicate Factories)

内置路由断言工厂

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories
网关启动日志:

image.png

路由断言主要用来判断路由的规则。
配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理。
例如Path=/user/**是按照路径匹配,这个规则是由
org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来处理。
像这样的断言工厂在SpringCloudGateway还有十几个:

名称 说明 示例
Path 基于请求路径进行匹配 - Path=/user/{params},/card/**
Method 基于请求方法(GET、POST等)进行匹配 - Method=GET,POST
Header 请求必须包含某些header - Header=asd, cas
Query 请求参数必须包含指定参数 - Query=name, Jack
Host 请求必须是访问某个host(域名) - Host=baidu.com, jd.com
Cookie 请求必须包含某些cookie - Cookie=chocolate
RemoteAddr 请求者的ip必须是指定范围 - RemoteAddr=192.168.1.1/24
After 是某个时间点后的请求 - After=2022-01-20T14:32:27.789-07:00[Asia/Shanghai]
Before 是某个时间点之前的请求 - Before=2022-04-13T15:14:47.433+08:00[Asia/Shanghai]
Between 是某两个时间点之前的请求 - Between=2021-01-20T17:42:47.789-07:00[Asia/Shanghai], 2023-01-21T17:42:47.789-07:00[Asia/Shanghai]
Weight 权重处理

自定义路由断言工厂

继承AbstractRoutePredicateFactory

在 Spring Cloud Gateway 中,自定义路由断言工厂(Custom Route Predicate Factory)是一种扩展机制,允许你定义自己的路由断言条件,以根据请求的特定属性或条件进行路由。
以下是创建自定义路由断言工厂的一般步骤:

  1. 创建自定义断言工厂类:创建一个类,实现 RoutePredicateFactory 接口,并重写相关方法。通常,你需要关注以下方法:
    • 类名应以 RoutePredicateFactory 结尾,使用驼峰命名法。例如,如果你的自定义断言工厂名为 CustomRoutePredicateFactory,则符合规范。
    • name():返回该断言工厂的名称,用于在配置文件中标识。
    • apply(Config config):根据配置信息创建并返回一个路由断言对象。
    • shortcutFieldOrder():返回一个列表,表示配置中字段的顺序。
  2. 以下是一个简单的例子:

当你创建自定义路由断言工厂时,可以通过以下步骤来详细了解如何实现:

  1. 创建自定义断言工厂类:
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

@Component
public class CustomRoutePredicateFactory extends AbstractRoutePredicateFactory<CustomRoutePredicateFactory.Config> {

    public CustomRoutePredicateFactory() {
        super(Config.class);
    }

    //这个方法主要用于创建并返回一个 Predicate<ServerWebExchange> 实例,该实例表示路由断言的条件。在网关的路由中,断言用于匹配传入的请求,以确定是否应该应用相应的路由规则。
    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return exchange -> {
            // 实现自定义的路由条件判断逻辑
            String path = exchange.getRequest().getURI().getPath();
            //返回 true 时,表示路由断言条件匹配,将应用相应的路由规则;当返回 false 时,表示路由断言条件不匹配,不会应用该路由规则。 
            return path.contains(config.getPath());
        };
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("path");
    }

    public static class Config {
        private String path;

        public String getPath() {
            return path;
        }

        public void setPath(String path) {
            this.path = path;
        }
    }
}

在这个例子中,我们创建了一个名为 CustomRoutePredicateFactory 的类,它继承了 AbstractRoutePredicateFactory。我们定义了一个配置类 Config,其中包含一个用于配置的字段 path。在 apply 方法中,我们实现了自定义的路由条件判断逻辑,判断请求的路径是否包含配置中的路径。

  1. 在配置文件中使用自定义断言工厂:
spring:
  cloud:
    gateway:
      routes:
        - id: custom_route
          uri: http://example.com
          predicates:
            - Custom=path:/custom

在配置文件中,我们使用了 Custom 断言工厂,并传递了配置参数 path:/custom。这个参数会被映射到 Config 类的 path 字段上。

通过这个自定义路由断言工厂,你可以根据项目的实际需求扩展路由的匹配条件。在 apply 方法中,你可以访问 ServerWebExchange 对象,从而获取请求的各种信息,并根据这些信息判断是否符合路由条件。这为你提供了很大的灵活性,可以实现各种自定义的路由策略。

  1. apply 方法的作用:
    这个方法主要用于创建并返回一个 Predicate 实例,该实例表示路由断言的条件。在网关的路由中,断言用于匹配传入的请求,以确定是否应该应用相应的路由规则。
  2. 返回值类型:
    返回的对象是一个 Predicate 实例。在 Java 中,Predicate 是一个函数式接口,它定义了一个接受一个参数并返回布尔值的方法。在这个上下文中,Predicate 表示一个用于判断 ServerWebExchange 对象是否符合特定条件的函数。返回 true 时,表示路由断言条件匹配,将应用相应的路由规则;当返回 false 时,表示路由断言条件不匹配,不会应用该路由规则。
  3. 实现逻辑:
    在你的 apply 方法中,你可以自定义逻辑来判断传入的请求是否满足你定义的条件。在你的例子中,实现的逻辑是判断请求的路径是否包含配置中指定的路径。

继承AbstractGatewayPredicateFactory

AbstractGatewayPredicateFactory 是 Spring Cloud Gateway 中用于创建 Gateway 断言工厂的抽象类。通过继承这个抽象类,你可以更容易地实现自定义的 Gateway 断言,定义路由匹配的规则。

  • 类名应以 GatewayPredicateFactory 结尾,使用驼峰命名法。
  • 例如,如果你的自定义断言工厂名为 CustomGatewayPredicateFactory,则符合规范。配置custom.

以下是关于 AbstractGatewayPredicateFactory 的一些要点:
1. 创建自定义的 Gateway Predicate 工厂:

import org.springframework.cloud.gateway.handler.predicate.AbstractGatewayPredicateFactory;

@Component
public class CustomGatewayPredicateFactory extends AbstractGatewayPredicateFactory<CustomGatewayPredicateFactory.Config> {

    public CustomGatewayPredicateFactory() {
        super(Config.class);
    }

    @Override
    public GatewayPredicate apply(Config config) {
        // 处理配置参数,例如 config.getParam()
        String param = config.getParam();

        // 返回自定义的 GatewayPredicate 实例
        return (exchange) -> {
            // 实现自定义的断言逻辑
            return exchange.getRequest().getQueryParams().containsKey(param);
        };
    }

    public static class Config {
        private String param;

        public String getParam() {
            return param;
        }

        public void setParam(String param) {
            this.param = param;
        }
    }
}

2. 在配置文件中使用自定义的 Gateway Predicate 工厂:
在路由配置中使用自定义的 Gateway Predicate 工厂,并为其提供配置参数。

spring:
  cloud:
    gateway:
      routes:
        - id: custom_gateway_predicate_route
          uri: http://example.com
          predicates:
            - Custom=param=value

两者的区别

AbstractRoutePredicateFactoryAbstractGatewayPredicateFactory 都是 Spring Cloud Gateway 中用于创建路由断言的抽象类,它们之间的主要区别在于使用场景和适用范围。

AbstractRoutePredicateFactory:
  1. 使用场景:
  • 适用于定义路由规则,通过匹配请求的各种属性(如路径、参数、头部等)来进行路由。
  • 通常涉及路由的核心逻辑,例如根据请求的路径、参数等条件进行路由选择。
  1. 示例:
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;

public class CustomRoutePredicateFactory extends AbstractRoutePredicateFactory<CustomRoutePredicateFactory.Config> {

    public CustomRoutePredicateFactory() {
        super(Config.class);
    }

    @Override
    public RoutePredicate apply(Config config) {
        // 实现自定义的断言逻辑
        return (exchange) -> exchange.getRequest().getQueryParams().containsKey(config.getParam());
    }

    public static class Config {
        private String param;

        public String getParam() {
            return param;
        }

        public void setParam(String param) {
            this.param = param;
        }
    }
}
AbstractGatewayPredicateFactory:
  1. 使用场景:
  • 适用于创建更复杂的 Gateway 断言,允许在断言中执行更复杂的逻辑、依赖注入其他组件,以及更多的定制化需求。
  • 提供了更多的灵活性,可以执行更广泛的逻辑,而不仅仅是路由规则的匹配。
  1. 示例:
import org.springframework.cloud.gateway.handler.predicate.AbstractGatewayPredicateFactory;

public class CustomGatewayPredicateFactory extends AbstractGatewayPredicateFactory<CustomGatewayPredicateFactory.Config> {

    public CustomGatewayPredicateFactory() {
        super(Config.class);
    }

    @Override
    public GatewayPredicate apply(Config config) {
        // 实现自定义的断言逻辑
        return (exchange) -> exchange.getRequest().getQueryParams().containsKey(config.getParam());
    }

    public static class Config {
        private String param;

        public String getParam() {
            return param;
        }

        public void setParam(String param) {
            this.param = param;
        }
    }
}
如何选择:
  • 如果只需简单的路由规则匹配,通常选择使用 AbstractRoutePredicateFactory
  • 如果需要更灵活、更复杂的断言逻辑,或者需要依赖注入其他组件,可以选择使用 AbstractGatewayPredicateFactory

在大多数情况下,使用 AbstractRoutePredicateFactory 就足够满足路由的需求。只有在需要更高度定制和复杂的逻辑时,才考虑使用 AbstractGatewayPredicateFactory。最终的选择取决于具体的业务需求和逻辑复杂性。

4.过滤器工厂( GatewayFilter Factories)

内置过滤器工厂

SpringCloudGateway 内置了很多的过滤器工厂,我们通过一些过滤器工厂可以进行一些业务逻辑处理器,比如添加剔除响应头,添加去除参数等
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories

SpringCloudGateWay目前已经提供了34种不同的过滤器工厂。


image.png
过滤器 作用 参数名 参数值 示例(filters配置) 备注
AddRequestHeader 添加请求头 name,value 添加的请求头及其值 AddRequestHeader=X-Request-red, blue
AddRequestParameter 在Query String中添加请求参数,参数值可以是变量,具体值可以从PATH或Host中匹配 name,value 添加的参数名及其值 AddRequestParameter=foo, bar-{segment}
AddResponseHeader 添加响应头
AddResponseHeader=X-Response-Red, Blue
DedupeResponseHeader 过滤重复响应头 name,strategy 需要过滤的响应头及策略(保留第一个,保留最后一个,保留唯一值 DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
CircuitBreaker 熔断器 name,fallbackUri,statusCodes 熔断器名称、熔断后的默认URI、熔断触发状态 - CircuitBreaker=myCircuitBreaker 使用熔断器需配置spring-cloud-starter-circuitbreaker-reactor-resilience4j,详见Resilience4J Documentation
FallbackHeaders 指定发生熔断时fallback响应头 executionExceptionTypeHeaderName, executionExceptionMessageHeaderName, rootCauseExceptionTypeHeaderName, rootCauseExceptionMessageHeaderName 异常类型、详情、根因类型、根因详情等响应头名称 executionExceptionTypeHeaderName: Test-Header
MapRequestHeader 添加新的请求头,值从已有请求头中获取 fromHeader,toHeader 已有请求头名称,新请求头名称 MapRequestHeader=Blue, X-Request-Red
PrefixPath 请求路径增加前缀 prefix 需增加的前缀 PrefixPath=/mypath
PreserveHostHeader 配置是否将原始请求头发送到服务方 PreserveHostHeader
RequestRateLimiter 请求频度控制 默认提供了基于Redis的频度控制过滤器,也可以自定义 默认提供了基于Redis的频度控制过滤器,也可以自定义
RedirectTo 重定向过滤器 status,url 重定向http status及重定向后的url RedirectTo=302, https://acme.org
RemoveRequestHeader 删除请求头 name 待删除的请求头 RemoveRequestHeader=X-Request-Foo
RemoveResponseHeader 删除响应头 name 待删除的响应头 RemoveResponseHeader=X-Response-Foo
RemoveRequestParameter 删除请求参数 name 待删除的请求参数名 RemoveRequestParameter=red
RewritePath 重写PATH egexp,replacement 重写部分匹配规则,需替换的值 RewritePath=/red/?(?<segment>.*), /$\{segment} 匹配规则采用正则表达式,替换值支持从匹配中获取
RewriteLocationResponseHeader 重写响应头中的Location stripVersionMode, locationHeaderName, hostValue, protocolsRegex path中version处理模式,location响应头名称,host值,url协议头 RewriteLocationResponseHeader=AS_IN_REQUEST, Location, ,
RewriteResponseHeader 重写响应头 name,regexp,replacement 响应头名称,需修改值的匹配规则,需替换的值 RewriteResponseHeader=X-Response-Red, , password=[^&]+, password=***
SaveSession 强制触发 SaveSession
SecureHeaders 添加一组安全相关的头信息到响应中 SecureHeaders
SetPath 设置请求path template path模板 SetPath=/{segment}
SetRequestHeader 设置请求头(不添加新的) name,value 请求头及其值 SetRequestHeader=X-Request-Red, Blue
SetResponseHeader 设置响应头(不添加新的) name,value 响应头及其值 SetResponseHeader=X-Response-Red, Blue
StripPrefix 截断请求PATH parts 需截断的长度(’/'个数) StripPrefix=2
SetStatus 设置响应状态 status 响应状态 SetStatus=401
Retry 重试过滤器 详细配置
RequestSize 限流器 maxSize 请求最大报文大小 maxSize: 5000000
SetRequestHostHeader 设置请求host host 分组及权重 SetRequestHostHeader=example.org
ModifyRequestBody 修改请求报文 只能通过 Java DSL 配置
ModifyResponseBody 修改响应报文 只能通过 Java DSL 配置
TokenRelay 配合OAuth2使用
CacheRequestBody 根据权重进行路由 bodyClass 请求体类型 详细配置

自定义过滤器工厂

注意自定义名称必须要以GatewayFilterFactory结尾并交给spring管理。前缀就是配置文件中的过滤器名称。

继承AbstractNameValueGatewayFilterFactory

AbstractNameValueGatewayFilterFactory 是 Spring Cloud Gateway 中的一个抽象类,用于简化自定义过滤器工厂的创建。它提供了一些便捷的方法,使得创建基于名称-值参数的过滤器工厂更加方便。

主要特点:
  1. 简化配置参数的处理: 通过继承 AbstractNameValueGatewayFilterFactory,你可以轻松地处理基于名称-值参数的配置。
  2. 适用于大多数场景: 对于大多数基于名称-值参数的过滤器,可以通过继承这个抽象类减少样板代码。
如何使用:

要使用 AbstractNameValueGatewayFilterFactory,只需继承它并提供一个配置类(Config),然后实现 apply 方法。以下是一个简单的例子:

import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;

@Component
public class CustomNameValueGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {

    @Override
    public GatewayFilter apply(NameValueConfig config) {
        // 通过 config.getName() 和 config.getValue() 获取参数
        String name = config.getName();
        String value = config.getValue();

        // 返回自定义的 GatewayFilter 实例
        return (exchange, chain) -> {
            // 实现自定义的过滤器逻辑
            System.out.println("Executing custom filter with name: " + name + ", value: " + value);
            // 继续执行过滤器链
            return chain.filter(exchange);
        };
    }
}

在上述例子中,NameValueConfigAbstractNameValueGatewayFilterFactory 内部的一个静态内部类,它继承自 AbstractNameValueDecoder,并提供了 getName()getValue() 方法。

配置方式:

在配置文件中,你可以像下面这样使用这个自定义过滤器工厂:

spring:
  cloud:
    gateway:
      routes:
        - id: custom_name_value_filter_route
          uri: http://example.com
          predicates:
            - Path=/custom/**
          filters:
          # 或者这样配:- CustomNameValue=customName,customValue
            - name: CustomNameValue
              args:
                name: customName
                value: customValue
                

在上述配置中,CustomNameValue 是我们自定义的过滤器工厂名称,namevalue 是参数,通过 NameValueConfiggetName()getValue() 方法获取。

继承AbstractGatewayFilterFactory

自定义过滤器工厂是 Spring Cloud Gateway 中用于创建自定义过滤器的机制。自定义过滤器工厂允许你定义和配置自己的网关过滤器,以满足特定的业务需求。下面详细讨论一下自定义过滤器工厂的主要方面:

1. 创建自定义过滤器工厂类:

创建一个继承自 AbstractGatewayFilterFactory 的类,并提供一个配置类(Config)以接收配置参数。

import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;

@Component
public class CustomGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomGatewayFilterFactory.Config> {

    public CustomGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        // 返回自定义的 GatewayFilter 实例
        return (exchange, chain) -> {
            // 实现自定义的过滤器逻辑
            System.out.println("Executing custom filter with parameter: " + config.getParam());
            // 继续执行过滤器链
            return chain.filter(exchange);
        };
    }

    public static class Config {
        private String param;

        public String getParam() {
            return param;
        }

        public void setParam(String param) {
            this.param = param;
        }
    }
}
2. 在配置文件中使用自定义过滤器工厂:

在路由配置中使用自定义过滤器工厂,并为其提供配置参数。

spring:
  cloud:
    gateway:
      routes:
        - id: custom_filter_route
          uri: http://example.com
          predicates:
            - Path=/custom/**
          filters:
            - name: Custom
              args:
                param: customParameterValue

全局过滤器(Global Filters)

内置全局过滤器

下面是几个常用的内置全局过滤器的示例说明:

过滤器类名 过滤器名称 配置示例 说明
org.springframework.cloud.gateway.filter.factory.AddRequestHeaderGatewayFilterFactory AddRequestHeader name: AddRequestHeader
args: name: Foo, value: Bar 向请求头中添加名为 "Foo",值为 "Bar" 的头部信息。
org.springframework.cloud.gateway.filter.factory.AddResponseHeaderGatewayFilterFactory AddResponseHeader name: AddResponseHeader
args: name: Foo, value: Bar 向响应头中添加名为 "Foo",值为 "Bar" 的头部信息。
org.springframework.cloud.gateway.filter.factory.HystrixGatewayFilterFactory Hystrix name: Hystrix
args: name: myCommand, fallbackUri: forward:/fallback 使用 Hystrix 实现熔断,命令名为 "myCommand",熔断后的默认 URI 为 "/fallback"。
org.springframework.cloud.gateway.filter.factory.RetryGatewayFilterFactory Retry name: Retry
args: retries: 3, statuses: BAD_GATEWAY 在发生异常时进行 3 次重试,只有当 HTTP 状态码为 BAD_GATEWAY 时才重试。
org.springframework.cloud.gateway.filter.factory.SetStatusGatewayFilterFactory SetStatus name: SetStatus
args: value: 404 设置响应的 HTTP 状态码为 404。

这些过滤器提供了在网关层面进行常见操作的便捷方式,开发者可以通过简单的配置就能实现添加头部、熔断、重试、修改状态码等功能,而不必编写额外的代码。这些内置的全局过滤器为开发者提供了更灵活、高效地进行网关配置的选项。

自定义全局过滤器

  1. 接口定义:
  • GlobalFilter 接口定义了一个 filter 方法,该方法用于实现全局过滤逻辑。
public interface GlobalFilter extends Ordered, GatewayFilter {
    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
  1. filter 方法:
  • filter 方法接受两个参数:ServerWebExchangeGatewayFilterChain
  • ServerWebExchange 代表当前请求和响应的上下文对象,可以用于获取请求、响应、属性等信息。
  • GatewayFilterChain 表示过滤器链,可以通过调用 chain.filter(exchange) 将请求传递给下一个过滤器。
  1. Ordered 接口:
  • GlobalFilter 继承了 Ordered 接口,该接口定义了一个 getOrder 方法,用于指定过滤器的执行顺序。
  • 过滤器的执行顺序通过该接口的 getOrder 方法返回的值确定,数值越小,优先级越高。
public interface Ordered {
    int getOrder();
}
  1. 使用示例:
  • 下面是一个简单的示例,展示了如何创建一个记录请求信息的全局过滤器。
  • 自定义全局过滤器类名在命名时没有特定的硬性规定。
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
//@Order(1) // 指定过滤器的执行顺序
@Component//自定义全局过滤器类名在命名时没有特定的硬性规定
public class LoggingGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("Request Path: " + exchange.getRequest().getPath());
        System.out.println("Request Method: " + exchange.getRequest().getMethod());
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}

在这个例子中,LoggingGlobalFilter 实现了 GlobalFilter 接口,通过 @Component 注解将其注册为 Spring Bean。该过滤器在请求进入网关时记录请求的路径和方法。

  1. 使用场景
  • 全局日志记录: 记录所有请求的信息,用于监控和分析。
  • 全局身份验证: 对所有请求进行身份验证,确保请求的安全性。
  • 全局头部添加: 在所有请求或响应中添加全局头部信息。
  • 性能监控: 统计请求的处理时间、成功率等性能指标。

注册

在 Spring Cloud Gateway 中,可以通过配置文件或者 Java 代码注册 GlobalFilter

使用配置文件注册

application.ymlapplication.properties 文件中,使用 spring.cloud.gateway.global-filters 属性指定全局过滤器的名称。

spring:
  cloud:
    gateway:
      global-filters:
        - LoggingGlobalFilter

使用 Java 代码注册:

通过创建一个配置类,使用 @Bean 注解注册 GlobalFilter

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GatewayConfig {

    @Bean
    public LoggingGlobalFilter loggingGlobalFilter() {
        return new LoggingGlobalFilter();
    }
}

5.附录

总结

使用gateway routes是常用的配置,

  • id 是路由的唯一标识
  • uri 是要路由的地址,有两种方法一种是注册中心的服务名,一种是URL
  • Predicate 符合要求的进行路由,内置Predicate能满足大部分需求
  • filters 过滤器,内置过滤器不能满足需求的情况下可以实现自定义过滤器

gateway完整配置

server:
  port: 8080

spring:
  cloud:
    gateway:
      routes: # 路由规则配置
        - id: route_example
          uri: http://example.com
          predicates:
            - Path=/example/**
          filters:
            - RewritePath=/example/(?<segment>.*), /$\{segment} # 重写路径为去除前缀的形式
            - AddRequestHeader=X-Request-Red, Blue # 添加请求头
            - AddResponseHeader=X-Response-Red, Green # 添加响应头

        - id: route_another
          uri: http://another-service.com
          predicates:
            - Path=/another/**
          filters:
            - StripPrefix=2 # 剥离请求路径前缀
            - RequestRateLimiter=Key=rateLimitKey, replenishRate=10, burstCapacity=20 # 请求速率限制
            - Retry=retries:3, statuses:500-599 # 请求重试
            - AddResponseHeader=X-Another-Header, Another-Value # 添加响应头

      default-filters: # 默认过滤器配置,应用于所有路由规则
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin # 确保响应头的唯一性

      default-uri: http://default-backend.com # 默认后备 URI,当没有匹配的路由规则时使用

      globalcors: # 全局跨域配置
        corsConfigurations:
          '[/**]':
            allowedOrigins: "*"
            allowedMethods:
              - GET
              - POST
            allowedHeaders:
              - "*"
            allowCredentials: true
            maxAge: 3600

在这个示例中,我们定义了两个路由规则(route_exampleroute_another),每个规则指定了URI、谓词(Predicate)、过滤器(Filter)。默认过滤器default-filters用于全局应用于所有路由,确保响应头的唯一性。默认后备URI default-uri 用于在没有匹配的路由规则时提供一个默认的后备服务。全局跨域配置globalcors用于设置跨域规则,确保所有路由都遵循相同的跨域设置。

spring.cloud.gateway.routes 子配置

以下是 spring.cloud.gateway.routes 配置的一些可能的子配置项,包括主要的和一些可选的配置。每个配置项的作用和示例都有说明:

spring:
  cloud:
    gateway:
      routes:
        - id: "route_example"
          uri: "http://example.com"
          order: 1
          predicates:
            - Path=/example/**
          filters:
            - RewritePath=/example/(?<segment>.*), /$\{segment}
            - AddRequestHeader=X-Request-Red, Blue
            - AddResponseHeader=X-Response-Red, Green
          metadata:
            foo: bar
            baz: qux
          description: "This is an example route"
          replace-response-header:
            - key: Content-Type
              value: application/json
配置项 示例 说明
id id: route_example 路由规则的唯一标识符,用于在配置中识别不同的路由。
uri uri: http://example.com 指定目标服务的URI,即请求将被路由到的目标地址。可以是具体的URL,也可以是注册在服务注册中心的服务名称。
predicates predicates: - Path=/example/** 谓词定义了请求的匹配条件,决定了是否应该应用当前路由规则。可以使用多个谓词组合。
filters filters: - RewritePath=/example/{segment} 过滤器用于对请求和响应进行处理。可以使用多个过滤器,按顺序执行。
order order: 1 用于指定路由规则的顺序。在多个路由规则匹配时,按照 order
的升序排列。数字越小优先级越高。
metadata metadata: foo: bar 元数据,可以在路由规则中添加自定义的元数据信息。这些信息可供后续使用。
description description: This is an example route. 路由规则的描述信息,可用于提供更详细的注释。
replace-response-header replace-response-header: - key: Content-Type value: application/json 用于替换响应头的配置,可以对响应头进行更灵活的操作。

这些配置项允许你根据实际的需求定义路由规则,并在路由规则中添加一些额外的信息,以便更好地管理和定制你的网关服务。

两种配置方式

声明式配置

spring:
  cloud:
    gateway:
      routes:
        - id: example_route1
          uri: http://example1.com
          predicates:
            - Path=/example1/**
        - id: example_route2
          uri: http://example2.com
          predicates:
            - Path=/example2/**

编程式配置

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.cloud.gateway.route.builder.RouteLocator;

@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("example_route1", r -> r
                .path("/example1/**")
                .uri("http://example1.com"))
            .route("example_route2", r -> r
                .path("/example2/**")
                .uri("http://example2.com"))
            .build();
    }
}

在这两个配置中,都定义了两个路由规则,分别将以 /example1/**/example2/** 开头的请求分别路由到 http://example1.comhttp://example2.com

总的来说,声明式配置更加简洁易读,适合静态路由规则;而编程式配置更加灵活,适合动态路由规则和更复杂的场景。根据具体的业务需求和团队偏好,可以选择合适的配置方式。

通配符

通配符的在 Spring Cloud Gateway 的 Predicate 中,支持使用通配符进行路径匹配。通配符主要用于简化路由规则中的路径匹配条件,使得可以匹配多个路径。以下是通配符的配置规则:

Path 谓词中的通配符:

  • *:匹配路径中的一个路径段。例如,/foo/*/bar 可以匹配 /foo/test/bar,但不能匹配 /foo/test/test/bar
  • **:匹配路径中的多个路径段,可以匹配任意路径。例如,/foo/**/bar 可以匹配 /foo/test/bar/foo/test/test/bar

以下是一个声明式配置的示例:

spring:
  cloud:
    gateway:
      routes:
        - id: example_route
          uri: http://example.com
          predicates:
            - Path=/foo/*/bar
        - id: another_route
          uri: http://example2.com
          predicates:
            - Path=/foo/**/bar

Query 谓词中的通配符

在查询参数中,可以使用通配符进行匹配。例如,Query=param1&param2=value* 可以匹配包含参数 param1 和以 value 开头的值的请求。

spring:
  cloud:
    gateway:
      routes:
        - id: query_route
          uri: http://example.com
          predicates:
            - Query=param1&param2=value*

通配符的配置规则主要用于简化路径和查询参数的匹配条件,使得可以更灵活地定义路由规则。

uri的多种配置方式

在 Spring Cloud Gateway 中,uri 的配置有多种写法,以适应不同的需求和场景。以下是几种常见的 uri 配置写法:

  1. 静态 URI:
    直接指定目标服务的静态 URI。
spring:
  cloud:
    gateway:
      routes:
        - id: static_uri_route
          uri: http://example.com
          predicates:
            - Path=/static/**

上述配置表示将匹配 /static/** 路径的请求转发到 http://example.com

  1. lb:// 负载均衡 URI:
    使用 lb:// 前缀指定服务注册中心中的服务名,进行负载均衡。
spring:
  cloud:
    gateway:
      routes:
        - id: lb_uri_route
          uri: lb://service-name
          predicates:
            - Path=/service/**

上述配置表示将匹配 /service/** 路径的请求转发到名为 service-name 的服务。

  1. Forward 转发 URI:
    使用 forward: 前缀指定一个内部转发的 URI。
spring:
  cloud:
    gateway:
      routes:
        - id: forward_uri_route
          uri: forward:/internal-service
          predicates:
            - Path=/internal/**

上述配置表示将匹配 /internal/** 路径的请求内部转发到 /internal-service。 "internal-service" 是相对于你的 Spring Cloud Gateway 应用程序内的一个路径。

  1. 合成 URI:
    使用 SpEL(Spring Expression Language)合成 URI,动态构建目标 URI。
spring:
  cloud:
    gateway:
      routes:
        - id: composite_uri_route
          uri: "'http://example.com' + T(java.time.LocalDate).now().toString()"
          predicates:
            - Path=/composite/**

上述配置表示将匹配 /composite/** 路径的请求,将目标 URI 合成为 http://example.com 加上当前日期。

这些是一些常见的 uri 配置写法,你可以根据实际需求选择适合你场景的方式。

全局过滤器执行顺序配置

@Order 注解和 getOrder() 方法同时存在时,@Order 注解的值会覆盖 getOrder() 方法返回的值。换句话说,如果使用了 @Order 注解,就会以注解的值为准,而忽略 getOrder() 方法的返回值。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容