路由网关
Spring Cloud 入门 ---- Gateway 路由网关
Gateway 介绍
简介
Gateway 是在 Spring 生态系统之上构建的 App 网关服务,基于 Spring 5,Spring Boot 2 和 Project Reactor 等技术。Gateway 旨在提供一种简单而有效的方式来对 API 进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试等。
Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul,在 Spring Cloud 2.0 以上的版本中,没有对新版本的 Zuul 2.0 以上最高性能版本进行集成,仍然还在使用 Zuul 1.x 非 Reactor 模式的老版本。而为了提高网关性能,Spring Cloud Gateway 是基于 WebFlux 框架实现的,而 WebFlux 框架底层使用了高性能的 Reactor 模式通信框架 Netty。
Spring Cloud Gateway 的目标是统一的路由方式且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。
官网:https://docs.spring.io/spring-cloud-gateway/docs/2.2.5.RELEASE/reference/html/#gateway-starter
特征
Spring Cloud Gateway 具有如下特征:
- 基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0 进行构建;
- 动态路由:能够匹配任何请求属性;
- 可以对路由指定 Predicate(断言)和 Filter(过滤器);
- 集成 Hystrix 的断路器功能;
- 集成 Spring Cloud 服务发现功能;
- 易于编写的 Predicate(断言)和 Filter(过滤器);
- 提供了请求限流功能;
- 支持路径重写;
三大核心概念
Route(路由):路由是构建网关的基本模块,它由 ID、目标 URI、一系列的断言和过滤器组成,如果断言为 true 则匹配该路由。
Predicate(断言):参考的是java 8 的 java.util.function.Predicate 开发人员可以匹配 HTTP 请求中的所有内容(例如:请求头或请求参数),如果请求头与断言匹配则进行路由。
Filter(过滤):指的是 Spring 框架中 GatewayFilter 的实例,使用过滤器,可以在请求被路由之前或之后对其进行修改。
总体流程
web 请求通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化控制,predicate 就是我们的匹配条件;而 filter 就可以理解为一个无所不能的拦截器。有了这两个元素,再加上 uri,就可以实现一个具体的路由了。
Gateway工作流程图
如图:客户端向 Spring Cloud Gateway 发送请求,然后 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler,Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。
过滤器之间用虚线分开,因为过滤器分为 发送到实际业务之前的过滤器(“pre”)和 发送到实际业务之后的过滤器(“post”);过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。
Filter 中 “pre” 类型的过滤器可以做【参数校验、权限校验、流量监控、日志输出、协议转换】等, “post” 类型的过滤器可以做【响应内容、响应头的修改,日志的输出,流量监控】等;它们都有着非常重要的作用。
Spring Cloud Gateway 于 Zuul 的区别
在 Spring Cloud Finchley 正式版之前,Spring Cloud 推荐到网关是 Netflix 提供的 Zuul;
Zuul 1.x,是一个基于阻塞 I/O 的 API Gateway,它
基于 Servlet 2.5 使用阻塞架构
,且不支持任何长连接(如 WebSocket),Zuul 的设计模式和 Nginx 较像,每次 I/O 操作都是从工作线程中选择一个执行,请求线程被阻塞到工作线程完成,但是差别是 Nginx 用 C++ 实现,Zuul 用 Java 实现,而 JVM 本身会有第一次加载较慢的情况,使得 Zuul 的性能相对较差。Spring Cloud Gateway 建立在 Spring Framework 5、Project Reactor 和 Spring Boot 2 之上,使用非阻塞 API,还支持 WebSocket,并且与 Spring 紧密集成拥有更好的开发体验。
在性能方面,根据官方提供的基准测试,Spring Cloud Gateway 的 RPS(每秒请求数)是 Zuul 的 1.6 倍。
Zuul 1.x 模型
Spring Cloud 所集成到 Zuul 1.x 版本,采用的是 Tomcat 容器,使用的是传统的 Servlet IO 处理模型。而 servlet 由 servlet container 进行生命周期管理。
- container 启动时构造 servlet 对象并调用 servlet init() 进行初始化;
- container 运行时接受请求,并为每个请求分配一个线程(一般从线程池中获取空闲线程)然后调用 service();
- container 关闭时调用 servlet destory() 销毁 servlet;
上述模式的缺点:
servlet 是一个简单的网络 IO 模型,当请求进入 servlet container 时,servlet container 就会为其绑定一个线程,在
并发不高的场景下
这种模型是适用的。但是一旦高并发(如抽风用 jemeter 压测),线程数量就会蹭蹭蹭地往上涨,而线程资源代价是昂贵的(上下文切换,内存消耗大)严重影响请求的处理时间。在一些简单业务场景下,不希望为每个 request 分配一个线程,只需要一个或几个线程就能应对极大并发的请求,这种业务场景下 servlet 模型就没有优势了,而 Zuul 1.x是基于 servlet 2.5 之上的一个阻塞式处理模型
。
传统的 Web 框架,比如说:struts2,springmvc 等都是基于 Servlet Api 与 Servlet 容器基础之上运行的。但是 在 Servlet 3.1 之后有了异步非阻塞的支持。而 WebFlux 是一个典型的非阻塞异步的框架,它的核心是基于 Reactor 的相关 API 实现的。相对于传统的 web 框架来说,它可以运行在诸如 Netty,Undertow及支持 Servlet 3.1 的容器上。非阻塞+函数式编程。Spring WebFlux 是 Spring 5.0 引入的新的响应式框架,区别于 Spring MVC,它不需要依赖 Servlet API,它是完全异步非阻塞的,并且基于 Reactor 来实现响应式流规范。
创建演示项目
注册中心沿用之前的 Eureka 模块,服务提供者沿用前面的 hystrix-provider-service8015 模块
基础演示模块
导入 pom 依赖,注意不要添加 web 模块依赖
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 引入 eureka client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
添加 application.yml 配置
server:
port: 6060
service-url:
payment-service: http://localhost:8015
spring:
application:
name: routing-gateway-service
security:
# 配置spring security登录用户名和密码
user:
name: akieay
password: 1qaz2wsx
cloud:
gateway:
routes:
- id: hystrix_provider_payment_ok # 路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: ${service-url.payment-service}/payment/hystrix/ok/{id} # 匹配后提供服务的路由地址
predicates:
- Path=/payment/hystrix/ok/{id} # 断言,路径相匹配的进行路由
- id: hystrix_provider_payment_timeout
uri: ${service-url.payment-service}/payment/hystrix/timeout/{id}
predicates:
- Path=/payment/hystrix/timeout/{id}
eureka:
client:
#表示是否将自己注册进 Eureka Server服务 默认为true
register-with-eureka: true
#f是否从Eureka Server抓取已有的注册信息,默认是true。单点无所谓,集群必需设置为true才能配合ribbon使用负载均衡
fetch-registry: true
service-url: # 设置与 Eureka Server 交互的地址 查询服务与注册服务都需要这个地址
# defaultZone: http://localhost:7001/eureka
defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@eureka7001.com:7001/eureka,http://${spring.security.user.name}:${spring.security.user.password}@eureka7002.com:7002/eureka
instance:
instance-id: routing-gateway-6060
## 当调用getHostname获取实例的hostname时,返回ip而不是host名
prefer-ip-address: true
# Eureka客户端向服务端发送心跳的时间间隔,单位秒(默认30秒)
lease-renewal-interval-in-seconds: 10
# Eureka服务端在收到最后一次心跳后的等待时间上限,单位秒(默认90秒)
lease-expiration-duration-in-seconds: 30
主启动
@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
启动 Eureka 注册中心,启动 hystrix-provider-service8015 服务提供者,启动 网关模块;注册中心查看信息
测试:访问:http://localhost:8015/payment/hystrix/ok/5 与 http://localhost:8015/payment/hystrix/timeout/15 可以看到访问正常,说明服务提供者能够正常提供服务
通过 gateway 网关访问服务:http://localhost:6060/payment/hystrix/ok/5 与 http://localhost:6060/payment/hystrix/timeout/15 可以看到,网关根据我们配置的地址信息,正确映射到了 服务提供者的地址。
两种网关路由配置方式
- 配置式:在配置文件 yml 中配置,由于前面已经做了演示,就不再演示了。
service-url:
payment-service: http://localhost:8015
spring:
application:
name: routing-gateway-service
cloud:
gateway:
routes:
- id: hystrix_provider_payment_ok # 路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: ${service-url.payment-service}/payment/hystrix/ok/{id} # 匹配后提供服务的路由地址
predicates:
- Path=/payment/hystrix/ok/{id} # 断言,路径相匹配的进行路由
- 编程式:在代码中注入
添加配置类
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("path_route2", r -> r.path("/guonei")
.uri("http://news.baidu.com/guonei"))
.route("path_route3", r -> r.path("/guoji")
.uri("http://news.baidu.com/guoji"))
.build();
}
}
重启服务,访问:http://localhost:6060/guonei 直接映射到了百度新闻页,如下图:
虽然有两种配置方式,但在使用中个人更推荐 yml 配置方式;
动态路由
默认情况下 Gateway 会根据注册中心注册的服务列表,以注册中心微服务名为路径创建
动态路由进行转发,从而实现动态路由的功能
。 演示:使用 Eureka 作为注册中心,hystrix-provider-service8015 与 hystrix-provider-service8016 作为服务提供者集群来演示动态路由。
修改 gateway 模块的 yml 配置,修改的部分如下【需要注意的是 uri 的协议为 lb,表示启用 Gateway 的负载均衡功能。】:
service-url:
payment-service: HYSTRIX-PROVIDER-SERVICE # 服务提供者的微服务名
spring:
cloud:
gateway:
discovery:
locator:
enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: hystrix_provider_payment_ok # 路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://${service-url.payment-service} # 匹配后提供服务的路由地址
predicates:
- Path=/payment/hystrix/ok/{id} # 断言,路径相匹配的进行路由
- id: hystrix_provider_payment_timeout
uri: lb://${service-url.payment-service}
predicates:
- Path=/payment/hystrix/timeout/{id}
另外修改 hystrix-provider-service,在 paymentInfo_OK 方法添加端口返回。
@GetMapping("/payment/hystrix/ok/{id}")
@HystrixCommand
public String paymentInfo_OK(@PathVariable("id") Integer id) {
String result = paymentService.paymentInfo_OK(id);
log.info("*******result: " + result + " 端口: " + serverPort);
return result + " 端口: " + serverPort;
}
重启服务,访问:http://localhost:6060/payment/hystrix/ok/15 ,即可看到 Gateway 动态路由的功能。
Gateway 常用的 Predicate
Spring Cloud Gateway 将路由匹配作为 Spring WebFlux HandlerMapping 基础架构的一部分。Spring Cloud Gateway 包括许多内置的 Route Predicate 工厂。所有这些 Predicate 都与 HTTP 请求的不同属性匹配。多个 Route Predicate 工厂可以进行组合,并通过逻辑 and。
Spring Cloud Gateway 创建 Route 对象时,使用 RoutePredicateFactory 创建 Predicate 对象,Predicate 对象可以赋值给 Route。Spring Cloud Gateway 包含许多内置的 Route Predicate Factories。
After Route Predicate
在指定时间之后的请求会匹配该路由。
spring:
cloud:
gateway:
routes:
- id: hystrix_provider_payment_ok # 路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://${service-url.payment-service} # 匹配后提供服务的路由地址
predicates:
- After=2020-11-09T23:40:39.840+08:00[Asia/Shanghai]
Before Route Predicate
在指定时间之前的请求会匹配该路由。
spring:
cloud:
gateway:
routes:
- id: hystrix_provider_payment_ok # 路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://${service-url.payment-service} # 匹配后提供服务的路由地址
predicates:
- Before=2021-02-09T23:40:39.840+08:00[Asia/Shanghai]
Between Route Predicate
在指定时间区间内的请求会匹配该路由。
spring:
cloud:
gateway:
routes:
- id: hystrix_provider_payment_ok # 路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://${service-url.payment-service} # 匹配后提供服务的路由地址
predicates:
- Between=2020-11-09T23:40:39.840+08:00[Asia/Shanghai], 2021-02-09T23:40:39.840+08:00[Asia/Shanghai]
由于以上三种配置规则类似,这里就演示只第三种;当前时间为:2020-11-09 23:47 配置如下:
重启 gateway 网关模块,访问:http://localhost:6060/payment/hystrix/ok/15,发现能够正常访问:
修改 yml 配置,重启服务,并访问:http://localhost:6060/payment/hystrix/ok/15 ,这时配置的时间区间为 2020-12-09 ~ 2021-02-09 当前时间不在这个区间内,路由不匹配,访问失败。
Cookie Route Predicate
带有指定Cookie的请求会匹配该路由。Cookie Route Predicate 需要两个参数,一个是 Cookie name,一个是正则表达式。路由规则会通过获取对应的 Cookie name 值和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行。
spring:
cloud:
gateway:
routes:
- id: hystrix_provider_payment_ok # 路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://${service-url.payment-service} # 匹配后提供服务的路由地址
predicates:
- Cookie=auth,akieay
使用 curl 工具测试,可直接在 windows 系统的命令行输入 curl 命令;curl 是常用的命令行工具,用来请求 Web 服务器。它的名字就是客户端(client)的 URL 工具的意思
不带指定 cookie 的访问,将报 404 错误
curl http://localhost:6060/payment/hystrix/ok/15
带指定 cookie 的访问,能够得到正常响应;当然由于中文存在一些乱码问题。
curl http://localhost:6060/payment/hystrix/ok/15 --cookie "auth=akieay"
Header Route Predicate
带有指定请求头的请求会匹配该路由。两个参数:一个是属性名称和一个正则表达式,这个属性值和正则表达式匹配则路由。
spring:
cloud:
gateway:
routes:
- id: hystrix_provider_payment_ok # 路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://${service-url.payment-service} # 匹配后提供服务的路由地址
predicates:
- Header=X-Request-Id, \d+ #请求头要有 X-Request-Id 属性并且值为整数的正则表达式
测试
curl http://localhost:6060/payment/hystrix/ok/15 -H "X-Request-Id:1604991617000"
Host Route Predicate
带有指定Host的请求会匹配该路由。
spring:
cloud:
gateway:
routes:
- id: hystrix_provider_payment_ok # 路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://${service-url.payment-service} # 匹配后提供服务的路由地址
predicates:
- Host=**.akieay.com, **.akieqh.com
测试
curl http://localhost:6060/payment/hystrix/ok/15 -H "Host:gateway.akieay.com"
Method Route Predicate
发送指定方法的请求会匹配该路由。
spring:
cloud:
gateway:
routes:
- id: hystrix_provider_payment_ok # 路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://${service-url.payment-service} # 匹配后提供服务的路由地址
predicates:
- Method=GET
测试,这里我们分别使用 GET 与 POST 请求访问,查看响应结果;可以发现 GET请求正常,POST 报 404。
curl http://localhost:6060/payment/hystrix/ok/15
curl -X POST http://localhost:6060/payment/hystrix/ok/15
Path Route Predicate
发送指定路径的请求会匹配该路由。
spring:
cloud:
gateway:
routes:
- id: path_route
uri: ${service-url.user-service}/user/{id}
predicates:
- Path=/payment/hystrix/ok/{id}
这个在前面一直有使用,就不单独演示了
Query Route Predicate
带指定查询参数的请求可以匹配该路由。
spring:
cloud:
gateway:
routes:
- id: path_route
uri: ${service-url.user-service}/user/{id}
predicates:
- Query=auth
测试
curl http://localhost:6060/payment/hystrix/ok/15?auth=akieay
RemoteAddr Route Predicate
从指定远程地址发起的请求可以匹配该路由。
spring:
cloud:
gateway:
routes:
- id: path_route
uri: ${service-url.user-service}/user/{id}
predicates:
- RemoteAddr=192.168.0.184/24
测试
curl http://192.168.0.184:6060/payment/hystrix/ok/15
Weight Route Predicate
使用权重来路由相应请求,以下表示有80%的请求会被路由到localhost:8201,20%会被路由到localhost:8202。
spring:
cloud:
gateway:
routes:
- id: weight_high
uri: http://localhost:8015
predicates:
- Weight=group1, 8
- id: weight_low
uri: http://localhost:8016
predicates:
- Weight=group1, 2
测试:访问 http://localhost:6060/payment/hystrix/ok/15,可以看到 8015 远比 8016 的调用次数多得多,比例接近我们设置的权重。
Gateway 常用的 Filter
路由过滤器可用于修改进入的 HTTP 请求和返回的 HTTP 响应,路由过滤器只能指定路由进行使用。Spring Cloud Gateway 内置了多种路由过滤器,它们都由 GatewayFilter 的工厂类来产生。
局部过滤器:https://docs.spring.io/spring-cloud-gateway/docs/2.2.5.RELEASE/reference/html/#gatewayfilter-factories
全局过滤器:https://docs.spring.io/spring-cloud-gateway/docs/2.2.5.RELEASE/reference/html/#global-filters
AddRequestHeader GatewayFilter
给请求添加
请求头
的过滤器。
spring:
cloud:
gateway:
routes:
- id: hystrix_provider_payment_timeout
uri: lb://${service-url.payment-service}
predicates:
- Path=/payment/hystrix/timeout/{id}
filters:
- AddRequestHeader=Authorization, Bearer fde5d867-b0c2-4bbc-aff6-ed8e72cf3e27
以上配置表示,在匹配的路由的
请求头
中添加我们指定的键值对,如下图:
AddRequestParameter GatewayFilter
给请求添加
请求参数
的过滤器。
spring:
cloud:
gateway:
routes:
- id: hystrix_provider_payment_timeout
uri: lb://${service-url.payment-service}
predicates:
- Path=/payment/hystrix/timeout/{id}
filters:
- AddRequestParameter=token, akieay.com
以上配置表示,在匹配的路由的
请求参数
中添加我们指定的键值对,如下图:
Hystrix GatewayFilter
Hystrix 过滤器允许我们将断路器功能添加到网关路由中,保护我们的服务免受级联故障的影响,并在发生下游故障时提供回退响应,保护我们的服务。
要开启断路器功能,需要我们在 pom 中引入 hystrix 依赖,并添加服务降级相关的处理类。
引入 pom 依赖
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
添加服务降级处理类
@RestController
public class FallbackController {
@GetMapping("/fallback")
public Object fallback() {
Map<String, Object> map = new HashMap<>();
map.put("data", null);
map.put("message", "common request fallback message");
map.put("code", 500);
return map;
}
}
修改 yml 配置
spring:
cloud:
gateway:
routes:
- id: hystrix_provider_payment_timeout
uri: lb://${service-url.payment-service}
predicates:
- Path=/payment/hystrix/timeout/{id}
filters:
- name: Hystrix
args:
name: fallbackcmd
fallback-uri: forward:/fallback
hystrix:
command: #用于控制HystrixCommand的行为
default:
execution:
isolation:
strategy: THREAD #控制HystrixCommand的隔离策略,THREAD->线程池隔离策略(默认),SEMAPHORE->信号量隔离策略
thread:
timeoutInMilliseconds: 5000 #配置HystrixCommand执行的超时时间,执行超过该时间会进行服务降级处理
重启服务,访问:http://localhost:6060/payment/hystrix/timeout/15 可以发现访问一切正常。
关闭服务提供者,访问:http://localhost:6060/payment/hystrix/timeout/15 即可看到,当服务不可用时,会调用我们指定的服务降级方法,返回友好提示。
RequestRateLimiter GatewayFilter
RequestRateLimiter 过滤器可以用于限流,使用 RateLimiter 实现来确定是否允许当前请求继续进行,如果请求太大默认会返回 HTTP 429-太多请求状态。
导入 pom 依赖
<!--redis reactive-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
添加限流策略配置类,这里指定了两种策略,一种根据请求参数进行限流,一种根据访问 IP 进行限流。
@Configuration
public class RedisRateLimiterConfig {
// @Bean
// public KeyResolver userKeyResolver() {
// return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("username"));
// }
@Bean
public KeyResolver ipKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
}
修改配置文件,添加限流策略配置 与 redis 配置信息
spring:
redis:
database: 0
host: 192.168.0.184
port: 6379
password: testakieay # 密码(默认为空)
timeout: 20000ms # 连接超时时长(毫秒)
jedis:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
cloud:
gateway:
routes:
- id: hystrix_provider_payment_ok # 路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://${service-url.payment-service} # 匹配后提供服务的路由地址
predicates:
- Path=/payment/hystrix/ok/{id} # 断言,路径相匹配的进行路由
filters:
- name: RequestRateLimiter
args:
# 每秒允许处理的请求数量
redis-rate-limiter.replenishRate: 1
# 每秒最大处理的请求数量
redis-rate-limiter.burstCapacity: 2
# 限流策略,对应策略的Bean
key-resolver: "#{@ipKeyResolver}"
重启服务,访问:http://localhost:6060/payment/hystrix/ok/15 可以看到当访问频率低时,可以正常访问,但一旦访问频率提高就会进入限流,如下图:
Retry GatewayFilter
对路由请求进行重试的过滤器,可以根据路由请求返回的 HTTP 状态码来确定是否进行重试。
spring:
cloud:
gateway:
routes:
- id: hystrix_provider_payment_ok # 路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://${service-url.payment-service} # 匹配后提供服务的路由地址
predicates:
- Path=/payment/hystrix/ok/{id} # 断言,路径相匹配的进行路由
filters:
- name: Retry
args:
retries: 2 #需要进行重试的次数
statuses: BAD_GATEWAY #返回哪个状态码需要进行重试,返回状态码为5XX进行重试
methods: GET,POST
backoff:
firstBackoff: 10ms
maxBackoff: 50ms
factor: 2
basedOnPreviousValue: false
修改服务提供者的 paymentInfo_OK 方法,重启服务提供者。
public String paymentInfo_OK(Integer id) {
if (id < 0) {
int i = 10 / 0;
}
return "线程池: " + Thread.currentThread().getName() + " paymentInfo_OK, id: " + id + "\t" + "(*^_^*)哈哈~";
}
重启网关服务,访问:http://localhost:6060/payment/hystrix/ok/-15 从控制台可以看到重试记录,1 次访问记录 + 2 次重试记录 共 3 次访问记录,如下图:
StripPrefix GatewayFilter
对指定数量的
路径前缀
进行去除的过滤器。
spring:
cloud:
gateway:
routes:
- id: hystrix_provider_payment_timeout
uri: lb://${service-url.payment-service}
predicates:
- Path=/a/b/payment/hystrix/timeout/{id}
filters:
- StripPrefix=2
测试:以上配置访问:http://localhost:6060/a/b/payment/hystrix/timeout/15 相当于访问:http://localhost:6060/payment/hystrix/timeout/15 过滤器会将请求前缀的两项【/a/b】去除掉;
PrefixPath GatewayFilter
与
StripPrefix
过滤器恰好相反的,会对原有路径前缀进行增加操作的过滤器。
spring:
cloud:
gateway:
routes:
- id: hystrix_provider_payment_timeout
uri: lb://${service-url.payment-service}
predicates:
- Path=/hystrix/timeout/{id}
filters:
- PrefixPath=/payment
测试:以上配置访问:http://localhost:6060/hystrix/timeout/15 相当于访问:http://localhost:6060/payment/hystrix/timeout/15 过滤器会将【/payment】拼接到请求的前缀上;
至此,常用的部分过滤器介绍完毕,至于其它的由于太多感兴趣的可以自行查阅。
自定义过滤器
添加配置类【注意下面这个是全局过滤器】,下面的过滤器指定请求中必须携带一个 token 参数;
@Component
@Slf4j
public class CustomFilter implements GlobalFilter, Ordered {
/**
* 过滤器逻辑处理
* @param exchange
* @param chain
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("************** come in CustomFilter **********");
String token = exchange.getRequest().getHeaders().getFirst("token");
if (StringUtils.isEmpty(token)) {
log.info("******* 用户凭证为空,非法用户,禁止访问/(ㄒoㄒ)/~~");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
/**
* 过滤器排序,数值低的先被调用
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
重启服务,这时的请求都必须在请求头中添加 token ,否则请求会返回我们自定义的 异常响应信息,如下图:
若是在请求头中加入 token,则能正常访问;如下图: