目录
2.2修改provider-service的ProviderController
2.3修改gateway的application.properties
一、网关介绍
上图中,采用微服务架构,客户端虽然可以直接访问后端服务,但这是有问题的:
- 微服务接口直接暴露在外网上,不安全
- 每个服务肯定需要:权限校验、接口监控、日志管理等这些通用的功能,如果各自为战,就会造成大量的代码冗余,而且不好维护
- 如果每个服务放在不同的服务器上(每个服务器ip不同),那么客户端需要维护一个ip列表才能访问,如果后端有数百个服务,客户端需要维护很大的列表。
针对以上问题,Spring推出网关服务 ,比如:
因此对于一个系统来说,网关就是系统的“检票口”,客户端的所有请求必须先到网关,经过“检票”后然后再转发到具体的服务。这样我们后面服务就无需直接暴露在外网上,提高了安全性。同时在“网关服务”这里还可以做一些所有服务通用的东西:验证权限、限流、错误码统一、缓存、日志、监控、告警等。
并且,将Spring Cloud Gateway注册到Nacos可以实现动态路由、服务发现、负载均衡、高可用性和配置管理等功能,显著提高微服务架构的灵活性和可维护性。通过Nacos的统一管理,Gateway可以更好地适应微服务架构的动态变化,简化运维工作,并与其他组件无缝集成。
二、SpringCloud Gateway介绍
Spring给我们提供了Spring Cloud Gateway 用来做网关服务,该项目基于Spring 5.0,Spring Boot 2.0。目的:为微服务架构提供一种简单的 API 管理方式。
其实,最开始时,Spring Cloud中是用Zuul的1.x版本来做网关的,不过这个版本不支持异步IO,而且长时间没有更新,于是Spring 就自己开发了一个Gateway来取代它。
三、配置文件方式实现转发路由(推荐)
1.创建一个Module——gateway
2.在 pom.xml中增加gateway的依赖
<dependencies>
<!--网关依赖gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
3.启动类
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
4.application.properties
server.port=7000
# 路由id,应保持唯一
# 命名规范:通常使用小写字母、数字和连字符(-)来命名,避免使用特殊字符或空格
spring.cloud.gateway.routes[0].id=my-custom-route
# 拦截地址
spring.cloud.gateway.routes[0].predicates[0]=Path=/hello
# 目标地址 provider-service
spring.cloud.gateway.routes[0].uri=http://localhost:8000
# 配置了一个id 为 my-custom-route 的路由规则,
# 当访问 http://localhost:7000/hello会自动转发到:http://localhost:8000/getPort
5.prvider-service
@RestController
public class ProviderController {
@Value("${server.port}")
private String port;
@GetMapping("/hello")
public String hello() {
return "hello provider---------" + port;
}
}
6.浏览器访问
启动gateway和provider-service后,在浏览器上访问:http://localhost:7000/hello
四、编码方式实现转发路由(不推荐)
1.注释掉gateway的配置文件
2.创建Config
@Configuration
public class Config {
// 配置路由
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("path_route", r -> r.path("/hello")
.uri("http://localhost:8000"))
.build();
}
}
3.浏览器访问
重启gateway后,在浏览器上访问:http://localhost:7000/hello
五、Gateway核心功能之——转发路由
(一)Path路径匹配
1.完全匹配
注释掉Config类,application.properties中的注释解开,重启gateway服务,浏览器访问:http://localhost:7000/aaa
会报错404
就是因为这个配置,所以才能正确跳转
spring.cloud.gateway.routes[0].predicates[0]=Path=/hello
而/aaa没有被拦截到,所以报找不到
2.Ant风格匹配
2.1Ant风格介绍
/a?: /ab
/a*: /ab 一个*只能匹配一个路径段
/a**:/ab /ab/a 多个*可以匹配多个路径段
2.2修改provider-service的ProviderController
@GetMapping("/getport")
public String getport() {
return "/getport---------" + port;
}
@GetMapping("/get/port")
public String port() {
return "/get/port---------" + port;
}
@GetMapping("/getp")
public String getp() {
return "getp---------" + port;
}
重启provider-service
2.3修改gateway的application.properties
spring.cloud.gateway.routes[0].predicates[0]=Path=/get*
重启gateway
2.4演示/get*路径匹配
这种是provider-service报错,/getaaa符合规则,但是provider-service没有这个接口:
这种是gateway报错,不符合路径匹配规则:
(二)Query 参数匹配
1. 匹配参数名
修改gateway的application.properties:
spring.cloud.gateway.routes[0].predicates[0]=Path=/get*
spring.cloud.gateway.routes[0].predicates[1]=Query=hero
这样配置,需要加上 name 参数,才能正常转发,比如:
如果没有hero参数就会报错:
2. 参数名和参数值匹配
修改gateway的application.properties:
spring.cloud.gateway.routes[0].predicates[0]=Path=/get*
spring.cloud.gateway.routes[0].predicates[1]=Query=hero,libai
3. 正则匹配
修改gateway的application.properties:
spring.cloud.gateway.routes[0].predicates[0]=Path=/get*
spring.cloud.gateway.routes[0].predicates[1]=Query=hero,t.
# ".":在正则中表示任意字符
(三)Method 请求方式匹配
修改gateway的application.properties:
spring.cloud.gateway.routes[0].predicates[0]=Path=/get*
spring.cloud.gateway.routes[0].predicates[1]=Query=hero,t.
# ".":在正则中表示任意字符
spring.cloud.gateway.routes[0].predicates[2]=Method=POST
# Method 可以配置为:POST、GET、PUT、DELETE,默认是GET
provider-service的ProviderController新增一个接口:
@PostMapping("/getport2")
public String getport2() {
return "/getport2---------" + port;
}
ApiFox测试:
注意:
- 这种predicates[1]=Query=hero,t.模式,必须是放在?后面
- post请求也得是放在params中的
(四)Cookie
修改gateway的application.properties:
spring.cloud.gateway.routes[0].predicates[0]=Path=/get*
spring.cloud.gateway.routes[0].predicates[1]=Query=hero,t.
# ".":在正则中表示任意字符
spring.cloud.gateway.routes[0].predicates[2]=Method=POST
# Method 可以配置为:POST、GET、PUT、DELETE,默认是GET
spring.cloud.gateway.routes[0].predicates[3]=Cookie=token,123456
# 表示 cookie 中要有 token 这个参数且值为123456,才能转发
spring.cloud.gateway.routes[0].predicates[0]=Path=/get*
spring.cloud.gateway.routes[0].predicates[1]=Query=hero,t.
# ".":在正则中表示任意字符
#spring.cloud.gateway.routes[0].predicates[2]=Method=POST
# Method 可以配置为:POST、GET、PUT、DELETE,默认是GET
spring.cloud.gateway.routes[0].predicates[2]=Cookie=token,123456
# 表示 cookie 中要有 token 这个参数且值为123456,才能转发
(五)时间范围匹配
其实就是对请求时间做限制,比如:新增一个接口,在今天晚上10点后才能访问
一共有 3 种使用方式:Before、After、Between
不过其采用 ZonedDateTime 的时间格式,也就是:2020-01-01T22:00:00+08:00[Asia/Shanghai]
1. Before
Before:匹配指定时间之前的请求,比如:
# 配置时间范围
spring.cloud.gateway.routes[0].predicates[3]=Before=2025-03-01T22:00:00+08:00[Asia/Shanghai]
2. After
After:匹配指定时间之后的请求
#可以用于一些接口定时开放
spring.cloud.gateway.routes[0].predicates[3]=After=2025-03-01T22:00:00+08:00[Asia/Shanghai]
3.Between
Between:匹配时间范围内的请求
spring.cloud.gateway.routes[0].predicates[3]=Between=2020-01-01T08:00:00+08:00[Asia/Shanghai],2020-01-02T08:00:00+08:00[Asia/Shanghai]
#这样配置,2020-01-01号早上8点 到 2020-01-02号早上8点 的请求能够访问
#可以用于一些接口限时访问
六、Gateway核心功能之——Filter过滤器
(一)Filter初体验
Gateway 中使用 Filter 来过滤请求,先体验一下,在 application.propertie 中使用下面的配置
server.port=7000
spring.cloud.gateway.routes[0].id=my-custom-route
spring.cloud.gateway.routes[0].predicates[0]=Path=/**
spring.cloud.gateway.routes[0].uri=http://localhost:8000
# 路径重写:将 /yase/getp 替换为 /getp
spring.cloud.gateway.routes[0].filters[0]=RewritePath=/yase/getp,/getp
结果:
上图在请求 /yase/getport 时,会自动把请求路径重写为 /getp,所以才能返回正确的结果。
另外,在 Gateway 中使用 Filter 有两种方式:
- 通过 spring.cloud.routes.filters 配置在具体的路由下,只作用在当前路由
- 通过 spring.cloud.default-filters 配置在全局,作用在所有路由上
这种配置方式可以保证接口的安全性,对外暴露的接口与实际的接口不一致,防止外部绕过网关访问服务。
(二)网关过滤器
使用 spring.cloud.routes.filters 方式配置的过滤器,称为:网关过滤器
Gateway 默认提供了一些网关过滤器:路径过滤器、参数过滤器、状态码过滤器等。
1. Path——路径过滤器
Path过滤器:本质就是对请求路径做一些修改,上面的RewritePath 就是其中的一种,其他还有:PrefixPath、StripPrefix、SetPath
1.1. RewritePath
RewritePath:对请求路径进行重写。好处:隐藏真实路径,提高安全性,方便用户记忆和输入等。最常见的是利用正则表达式重写 url,正则表达式学习网站:https://regex101.com/
RewritePath=/test(?<value>\/.*), $\{value}
#利用正则去重写url,把/test/it,重写为/it
#正则表达式并不是这节课的重点,但是这个用法比较少见,简单的解释一下
#"()":括号在正则中是组的意思,可以理解为里面的东西是一体的
#"?<value>":相当于在正则中声明了一个名字为value的变量,格式:?<变量名>
#"\/.*":匹配以"/"开头的所有字符,其中“\”是转义字符
# \是反斜杠;/是正斜杠
# (?<value>\/.*)整体的意思是:匹配"/test"后面,第一个字符是"/"且之后的所有字符,并把匹配到的字符串赋给value变量
# $\{value} :使用 value 变量
spring.cloud.gateway.routes[0].filters[0]=RewritePath=/test(?<value>\/.*), $\{value}
1.2. PrefixPath
PrefixPath:为url添加指定的前缀,比如:
#为url添加指定的前缀
spring.cloud.gateway.routes[0].filters[0]=PrefixPath=/get
# 配置后 /port 会重写为 /get/port
1.3. StripPrefix
StripPrefix:配置一个数字,表示从请求中剥离 n 个路径,比如:
#转发之前从请求中剥离n个路径
spring.cloud.gateway.routes[0].filters[0]=StripPrefix=2
# 配置后 /aa/bb/getPort 会重写为 /getPort
1.4. SetPath
SetPath:一般配合 Path 使用,比如:
spring.cloud.gateway.routes[0].predicates[0]=Path=/**
spring.cloud.gateway.routes[0].uri=http://localhost:8000
# 借用 predicates 中的value,无论什么请求,都会转发到/getport
spring.cloud.gateway.routes[0].filters[0]=SetPath=/getport
spring.cloud.gateway.routes[0].predicates[0]=Path=/get/{value}
spring.cloud.gateway.routes[0].uri=http://localhost:8000
# 借用 predicates 中的value,无论什么请求,都会转发到/{value}
spring.cloud.gateway.routes[0].filters[0]=SetPath=/{value}
2.Parameter——参数过滤器
可以给请求上添加一些参数,比如:
server.port=7000
spring.cloud.gateway.routes[0].id=my-custom-route
spring.cloud.gateway.routes[0].predicates[0]=Path=/get/{value}
spring.cloud.gateway.routes[0].uri=http://localhost:8000
spring.cloud.gateway.routes[0].filters[0]=SetPath=/{value}
spring.cloud.gateway.routes[0].filters[1]=AddRequestParameter=name,test
3.其他过滤器
过滤器中最顶级的接口是 GatewayFilterFactory,它还有很多其他子类,但不一一介绍
在配置文件中添加的配置都是下面实现类的前缀:
(三)全局过滤器
server.port=7000
# 路由id,应保持唯一
# 命名规范:通常使用小写字母、数字和连字符(-)来命名,避免使用特殊字符或空格
spring.cloud.gateway.routes[0].id=my-custom-route
spring.cloud.gateway.routes[0].predicates[0]=Path=/getport
spring.cloud.gateway.routes[0].uri=http://localhost:8000
spring.cloud.gateway.routes[0].filters[0]=AddRequestParameter=name,test
# 默认过滤器
spring.cloud.gateway.default-filters[0]=AddResponseHeader=token,123456
spring.cloud.gateway.routes[1].id=my-custom-route2
spring.cloud.gateway.routes[1].predicates[0]=Path=/getp
spring.cloud.gateway.routes[1].uri=http://localhost:8000
查看每个请求的header:全局过滤器配置多个路由都生效
(四)自定义过滤器
自定义Filter是我们最常使用的,因为在这里我们才能编写自己项目独有的业务,比如:token验证。同样,自定义过滤器也分为两种: 自定义网关过滤器、自定义全局过滤器。
1. 自定义Gateway Filter
1.1第一种方式
注释掉这段配置:
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 自定义网关过滤器需要实现两个接口:GatewayFilter, Ordered
*/
public class MyGatewayFilter implements GatewayFilter, Ordered {
/**
*
* @param exchange 可以认为是session
* @param chain 过滤器链
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("自定义网关过滤器:CustomGatewayFilter");
ServerHttpRequest request = exchange.getRequest();
System.out.println(request.getPath().value());
return chain.filter(exchange); // 执行下一个过滤器
// 如果不写return,则请求不会被过滤
}
/**
* 过滤器执行顺序,数值越小,优先级越高
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
使用自定义过滤器:
@Configuration
public class Config {
// 配置路由
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("path_route", r -> r.path("/getp")
.filters(f->f.filter(new MyGatewayFilter()))
.uri("http://localhost:8000"))
.build();
}
}
http://localhost:7000/getp 结果:
1.2第二种方式
这种方式可以在 propeties 中使用过滤器,之前在 properties 中使用的都是内置的过滤器,想要自定义,先看看内置过滤器是如何实现的:
以 RewritePathGatewayFilterFactory 为例,其核心方法是 apply,打上断点
Config是RewritePathGatewayFilterFactory中的内部类,目的:接收 properties 中的配置
appliy方法在系统启动时运行,返回一个GatewayFilter类型的对象(其实就是网关过滤器)
- 在GatewayFilter 对象的 filter 中,书写我们自己的业务逻辑
RewritePathGatewayFilterFactory 的其他代码:
模仿内置的 RewritePathGatewayFilterFactory ,自定义一个过滤器:
先注释掉Config类
server.port=7000
# 路由id,应保持唯一
# 命名规范:通常使用小写字母、数字和连字符(-)来命名,避免使用特殊字符或空格
spring.cloud.gateway.routes[0].id=my-custom-route
spring.cloud.gateway.routes[0].predicates[0]=Path=/getport
spring.cloud.gateway.routes[0].uri=http://localhost:8000
#spring.cloud.gateway.routes[0].filters[0]=AddRequestParameter=name,test
# 自定义过滤器
spring.cloud.gateway.routes[0].filters[0]=MyRewrite=name,yase
# 默认全局过滤器
spring.cloud.gateway.default-filters[0]=AddResponseHeader=token,123456
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.List;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
/***
* @className: MyRewriteGatewayFilterFactory
* @author: lxm
* @description:
* @date: 2025/2/25 1:25
* @version: 0.1
* @since :jdk11
*/
@Component
public class MyRewriteGatewayFilterFactory extends AbstractGatewayFilterFactory<MyRewriteGatewayFilterFactory.Config> {
public MyRewriteGatewayFilterFactory() {
super(MyRewriteGatewayFilterFactory.Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
// 配置参数 属性名是key,参数值是value
return Arrays.asList("key", "value");
}
@Override
public GatewayFilter apply(MyRewriteGatewayFilterFactory.Config config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest oldRequest = exchange.getRequest();
String path = oldRequest.getURI().getRawPath();
String newPath = path + "?" + config.getKey() + "=" + config.getValue();
ServerHttpRequest newRequest = oldRequest.mutate().path(newPath).build();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());
return chain.filter(exchange.mutate().request(newRequest).build());
}
};
}
public static class Config {
private String key;
private String value;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
重启后,浏览器访问:http://localhost:7000/getport
转发前修改路径:
转发后改变请求参数:
2. 自定义全局过滤器
自定义全局过滤器,在开发中使用最多的,像限流、权限校验、统计接口耗时等都用它来实现。
比如:判断请求中token参数的值,如果token不对,那么直接返回:没有权限
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 自定义全局过滤器,实现两个接口:GatewayFilter, Ordered
*/
@Component//最好通过这个注解,把CustomGlobalFilter注册到spring中
public class CustomGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
//获取请求上的参数
MultiValueMap<String, String> queryParams = request.getQueryParams();
//拿到token
String token = queryParams.getFirst("token");
if(StringUtils.isEmpty(token)){
//如果token为空,直接返回:没有权限
final ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().add("Content-type"
,"application/json; charset=utf-8");
String msg = "{\"message\":\"没有权限\"}";
DataBuffer buffer = response.bufferFactory().wrap(msg.getBytes());
return response.writeWith(Mono.just(buffer));
}
//如果token不是空,进行下一步
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
server.port=7000
spring.cloud.gateway.routes[0].id=my-custom-route
spring.cloud.gateway.routes[0].predicates[0]=Path=/getport
spring.cloud.gateway.routes[0].uri=http://localhost:8000
# 自定义过滤器
spring.cloud.gateway.routes[0].filters[0]=MyRewrite=name,yase
自定义全局过滤器(如 CustomGlobalFilter)通常是通过注解 @Component 自动注册到 Spring 上下文中的,因此不需要在 application.properties 文件中进行额外的配置来启用它。Spring Boot 会自动扫描带有 @Component 注解的类并将其注册为 Bean。
七、Gateway集成Nacos
1.gateway的pom.xml文件添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
2.修改application.properties文件
注释掉自定义全局过滤器CustomGlobalFilter
server.port=7000
spring.application.name=gateway-service
spring.cloud.nacos.discovery.server-addr=192.168.157.102:8848
spring.cloud.gateway.routes[0].id=my-custom-route
spring.cloud.gateway.routes[0].predicates[0]=Path=/**
# lb表示负载均衡load balance
spring.cloud.gateway.routes[0].uri=lb://provider-service
# 自定义过滤器
spring.cloud.gateway.routes[0].filters[0]=MyRewrite=name,yase
# 默认全局过滤器
spring.cloud.gateway.default-filters[0]=AddResponseHeader=token,123456
3.查看Nacos的服务列表
4.注册到Nacos上后,也可以正常请求转发
5.测试负载均衡
启动这三个服务:
负载均衡默认使用轮询成功:
八、Gateway集成Sentinel
1.pom.xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<!-- 引入sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2.application.properties
server.port=7000
spring.application.name=gateway-service
spring.cloud.nacos.discovery.server-addr=192.168.157.102:8848
spring.cloud.gateway.routes[0].id=my-custom-route
spring.cloud.gateway.routes[0].predicates[0]=Path=/**
# lb表示负载均衡load balance
spring.cloud.gateway.routes[0].uri=lb://provider-service
# 自定义过滤器
spring.cloud.gateway.routes[0].filters[0]=MyRewrite=name,yase
# 默认全局过滤器
spring.cloud.gateway.default-filters[0]=AddResponseHeader=token,123456
spring.cloud.sentinel.transport.dashboard=192.168.157.102:8080
spring.cloud.sentinel.transport.client-ip=192.168.0.16
#Sentinel客户端通信端口,该端口负责跟Sentinel应用通信,默认是8719
spring.cloud.sentinel.transport.port=8719
3.启动sentinel并设置流控规则
设置流控规则:
该接口访问第二次的时候会失效:
4.分组API设置流控规则
删除原有请求链路,配置新的API分组管理:
5.请求测试
只有a分组下的/getp接口1秒内请求超过2次会失效:
b分组因为没有设置流控规则,所以不会失效:
6.自定义异常
注释掉Config
新建 GatewayConfig
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import javax.annotation.PostConstruct;
import java.util.HashMap;
@Configuration
public class GatewayConfig {
@PostConstruct // 用于标识一个方法应该在依赖注入完成之后、初始化之前执行。
public void init() {
BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable t) {
// 自定义异常处理
HashMap<String, String> map = new HashMap<>();
map.put("code", "10099");
map.put("message", "服务器忙,请稍后再试!");
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(map));
}
};
GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}
}
如果sentinel没有做持久化,之前的API分组会失效,我们直接重新配置流控规则: