1. 什么是Spring Cloud Gateway
Spring Cloud Gateway是Spring Cloud生态系统中的一个组件,用于构建基于Spring Boot的微服务架构中的网关服务。网关是系统的入口点,它负责接收所有外部请求,并根据一定的规则将请求路由到相应的微服务。以下是Spring Cloud Gateway的主要特性和用途:
特性
- 动态路由: Spring Cloud Gateway支持动态路由,这意味着可以在运行时动态地添加、修改或删除路由规则。这为系统的灵活性和可维护性提供了便利。
- 谓词和过滤器: 路由规则由谓词和过滤器组成。谓词用于匹配请求的条件,而过滤器用于在请求被路由前或路由后执行一些操作,如修改请求、响应、添加请求头等。
- 集成性: Spring Cloud Gateway可以与Spring Cloud生态系统中的其他组件(如服务注册中心、配置中心、Security等)无缝集成,为微服务架构提供全面的支持。
- 熔断和限流: Spring Cloud Gateway集成了熔断器和限流器,可以有效地保护微服务免受过载和故障的影响。熔断器用于处理故障,限流器用于控制请求的速率。
- 动态刷新: Spring Cloud Gateway支持动态刷新配置,使得可以在运行时动态修改配置,而无需重新启动网关服务。
- WebSocket支持: Spring Cloud Gateway对WebSocket提供了支持,可以轻松地处理WebSocket流量并进行路由。
- 统一的入口点: 通过网关,可以实现对微服务架构的统一入口点管理,从而简化了系统的管理和维护。
用途
- 路由: Spring Cloud Gateway充当系统的请求入口,根据路由规则将请求转发到相应的微服务。这有助于实现统一的请求处理和路由策略。
- 过滤: 可以使用过滤器执行各种任务,如身份验证、日志记录、请求修改等。这使得可以在网关层面处理与请求和响应相关的横切关注点。
- 熔断和限流: 通过集成熔断器和限流器,可以提高系统的稳定性,防止微服务由于过载或故障而崩溃。
- 统一管理: 通过集成Spring Cloud生态系统的其他组件,可以实现微服务架构的全面管理,包括服务注册、配置管理、安全性等。
- 动态配置: 可以动态地添加、修改或删除路由规则,而无需重新启动网关服务,从而提高系统的灵活性。
总体而言,Spring Cloud Gateway是构建现代化、分布式应用程序的重要工具,通过提供灵活的路由和过滤机制,有助于简化微服务架构的管理和维护。它为开发人员提供了一种强大而灵活的方式,以满足不同应用场景的需求。
核心概念
- 路由(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 两种。
- 客户端向 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)测试
3. 路由主要有四个配置
- 路由id(id):id用于唯一标识一个路由规则,可以通过该标识符进行管理和操作。
- 路由目标(uri):uri指定了该路由规则要将请求转发到的目标服务的基本URI。这可以是一个外部服务的URL,也可以是注册在服务注册中心的服务名。
- 路由断言(predicates):predicates定义了路由规则的匹配条件,即何种情况下该路由规则应该生效。谓词通常包括路径、方法、请求头等条件。
- 路由过滤器(filters):filters定义了路由规则应用的过滤器,过滤器在请求被路由前或路由后执行一些操作,如修改请求、修改响应、添加请求头等。
Predicates 和 Filters 是构建路由规则的基本元素。Predicates 用于匹配请求的条件,而 Filters 用于对请求和响应进行处理。它们是通过链式调用的方式组成的过滤器链。
3.断言工厂(Route Predicate Factories)
内置路由断言工厂
路由断言主要用来判断路由的规则。
配置文件中写的断言规则只是字符串,这些字符串会被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)是一种扩展机制,允许你定义自己的路由断言条件,以根据请求的特定属性或条件进行路由。
以下是创建自定义路由断言工厂的一般步骤:
-
创建自定义断言工厂类:创建一个类,实现 RoutePredicateFactory 接口,并重写相关方法。通常,你需要关注以下方法:
- 类名应以 RoutePredicateFactory 结尾,使用驼峰命名法。例如,如果你的自定义断言工厂名为 CustomRoutePredicateFactory,则符合规范。
- name():返回该断言工厂的名称,用于在配置文件中标识。
- apply(Config config):根据配置信息创建并返回一个路由断言对象。
- shortcutFieldOrder():返回一个列表,表示配置中字段的顺序。
- 以下是一个简单的例子:
当你创建自定义路由断言工厂时,可以通过以下步骤来详细了解如何实现:
- 创建自定义断言工厂类:
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
方法中,我们实现了自定义的路由条件判断逻辑,判断请求的路径是否包含配置中的路径。
- 在配置文件中使用自定义断言工厂:
spring:
cloud:
gateway:
routes:
- id: custom_route
uri: http://example.com
predicates:
- Custom=path:/custom
在配置文件中,我们使用了 Custom
断言工厂,并传递了配置参数 path:/custom
。这个参数会被映射到 Config
类的 path
字段上。
通过这个自定义路由断言工厂,你可以根据项目的实际需求扩展路由的匹配条件。在 apply
方法中,你可以访问 ServerWebExchange
对象,从而获取请求的各种信息,并根据这些信息判断是否符合路由条件。这为你提供了很大的灵活性,可以实现各种自定义的路由策略。
- apply 方法的作用:
这个方法主要用于创建并返回一个 Predicate 实例,该实例表示路由断言的条件。在网关的路由中,断言用于匹配传入的请求,以确定是否应该应用相应的路由规则。- 返回值类型:
返回的对象是一个 Predicate 实例。在 Java 中,Predicate 是一个函数式接口,它定义了一个接受一个参数并返回布尔值的方法。在这个上下文中,Predicate 表示一个用于判断 ServerWebExchange 对象是否符合特定条件的函数。返回 true 时,表示路由断言条件匹配,将应用相应的路由规则;当返回 false 时,表示路由断言条件不匹配,不会应用该路由规则。- 实现逻辑:
在你的 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
两者的区别
AbstractRoutePredicateFactory
和 AbstractGatewayPredicateFactory
都是 Spring Cloud Gateway 中用于创建路由断言的抽象类,它们之间的主要区别在于使用场景和适用范围。
AbstractRoutePredicateFactory:
- 使用场景:
- 适用于定义路由规则,通过匹配请求的各种属性(如路径、参数、头部等)来进行路由。
- 通常涉及路由的核心逻辑,例如根据请求的路径、参数等条件进行路由选择。
- 示例:
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:
- 使用场景:
- 适用于创建更复杂的 Gateway 断言,允许在断言中执行更复杂的逻辑、依赖注入其他组件,以及更多的定制化需求。
- 提供了更多的灵活性,可以执行更广泛的逻辑,而不仅仅是路由规则的匹配。
- 示例:
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种不同的过滤器工厂。
过滤器 | 作用 | 参数名 | 参数值 | 示例(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 中的一个抽象类,用于简化自定义过滤器工厂的创建。它提供了一些便捷的方法,使得创建基于名称-值参数的过滤器工厂更加方便。
主要特点:
-
简化配置参数的处理: 通过继承
AbstractNameValueGatewayFilterFactory
,你可以轻松地处理基于名称-值参数的配置。 - 适用于大多数场景: 对于大多数基于名称-值参数的过滤器,可以通过继承这个抽象类减少样板代码。
如何使用:
要使用 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);
};
}
}
在上述例子中,NameValueConfig
是 AbstractNameValueGatewayFilterFactory
内部的一个静态内部类,它继承自 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
是我们自定义的过滤器工厂名称,name
和 value
是参数,通过 NameValueConfig
的 getName()
和 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。 |
这些过滤器提供了在网关层面进行常见操作的便捷方式,开发者可以通过简单的配置就能实现添加头部、熔断、重试、修改状态码等功能,而不必编写额外的代码。这些内置的全局过滤器为开发者提供了更灵活、高效地进行网关配置的选项。
自定义全局过滤器
- 接口定义:
-
GlobalFilter
接口定义了一个filter
方法,该方法用于实现全局过滤逻辑。
public interface GlobalFilter extends Ordered, GatewayFilter {
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
- filter 方法:
-
filter
方法接受两个参数:ServerWebExchange
和GatewayFilterChain
。 -
ServerWebExchange
代表当前请求和响应的上下文对象,可以用于获取请求、响应、属性等信息。 -
GatewayFilterChain
表示过滤器链,可以通过调用chain.filter(exchange)
将请求传递给下一个过滤器。
- Ordered 接口:
-
GlobalFilter
继承了Ordered
接口,该接口定义了一个getOrder
方法,用于指定过滤器的执行顺序。 - 过滤器的执行顺序通过该接口的
getOrder
方法返回的值确定,数值越小,优先级越高。
public interface Ordered {
int getOrder();
}
- 使用示例:
- 下面是一个简单的示例,展示了如何创建一个记录请求信息的全局过滤器。
- 自定义全局过滤器类名在命名时没有特定的硬性规定。
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。该过滤器在请求进入网关时记录请求的路径和方法。
- 使用场景
- 全局日志记录: 记录所有请求的信息,用于监控和分析。
- 全局身份验证: 对所有请求进行身份验证,确保请求的安全性。
- 全局头部添加: 在所有请求或响应中添加全局头部信息。
- 性能监控: 统计请求的处理时间、成功率等性能指标。
注册
在 Spring Cloud Gateway 中,可以通过配置文件或者 Java 代码注册 GlobalFilter
。
使用配置文件注册
在 application.yml
或 application.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_example
和route_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.com
和 http://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¶m2=value*
可以匹配包含参数 param1
和以 value
开头的值的请求。
spring:
cloud:
gateway:
routes:
- id: query_route
uri: http://example.com
predicates:
- Query=param1¶m2=value*
通配符的配置规则主要用于简化路径和查询参数的匹配条件,使得可以更灵活地定义路由规则。
uri的多种配置方式
在 Spring Cloud Gateway 中,uri
的配置有多种写法,以适应不同的需求和场景。以下是几种常见的 uri
配置写法:
-
静态 URI:
直接指定目标服务的静态 URI。
spring:
cloud:
gateway:
routes:
- id: static_uri_route
uri: http://example.com
predicates:
- Path=/static/**
上述配置表示将匹配 /static/**
路径的请求转发到 http://example.com
。
-
lb:// 负载均衡 URI:
使用lb://
前缀指定服务注册中心中的服务名,进行负载均衡。
spring:
cloud:
gateway:
routes:
- id: lb_uri_route
uri: lb://service-name
predicates:
- Path=/service/**
上述配置表示将匹配 /service/**
路径的请求转发到名为 service-name
的服务。
-
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 应用程序内的一个路径。
-
合成 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() 方法的返回值。