网关简介
大家都都知道在微服务架构中,一个系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢?如果没有网关的存在,我们只能在客户端记录每个微服务的地址,然后分别去用。
这样架构会存在很多问题:
- 每个业务都会需要鉴权、限流、权限校验、跨域等逻辑,
如果每个业务都各自为战,自己造轮子实现一遍
,会很蛋疼,完全可以抽出来,放到一个统一的地方去做。 - 如果业务量比较简单的话, 这种方式前期不会有什么问题,但随着业务越来越复杂,比如淘宝、亚马逊,打开一个页面可能会涉及到数百个微服务协同工作,
如果每一个微服务都分配一个域名的话,一方面客户端代码会很难维护,涉及到数百个域名,另一方面是连接数的瓶颈
,想象一 下你打开一个APP,通过抓包发现涉及到了数百个远程调用,这在移动端下会显得非常低效。 - 后期如果需要对微服务进行重构的话, 也会变的非常麻烦,需要客户端配合你一起进行改造,比如商品服务,随着业务变的越来越复杂,
后期需要进行拆分成多个微服务,这个时候对外提供的服务也需要拆分成多个
,同时需要客户端配合你进行改造,非常蛋疼。
上面的问题可以借助 API 网关来解决。
注重稳定性:
- 全局性流控
- 日志统计
- 防止 SQL 注入
- 防止 Web 攻击
- 屏蔽工具扫描
- 黑白 IP 名单
- 证书/加解密处理
提供更好的服务
- 服务级别流控
- 服务降级与熔断
- 路由与负载均衡、灰度策略
- 服务过滤、聚合与发现
- 权限验证与用户等级策略
- 业务规则与参数校验
- 多级缓存策略
所谓的API网关,就是指系统的统一入口,它封装了应用程序的内部结构,为客户端提供统一服务,一 些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、路由转发等等。添加上API网关之后,系统的架构图变成了如下所示:
一、什么是 Spring Cloud Gateway
网关作为流量的入口,常用的功能包括路由转发,权限校验,限流等。
Spring Cloud Gateway 是 Spring Cloud 官方推出的第二代网关框架,定位于取代 Netlix Zuul。相比Zuul 来说,Spring Cloud Gateway 提供更优秀的性能,更强大的有功能。
Spring Cloud Gateway 由 WebFlux + Netty + Reactor 实现的响应式的 API 网关。它不能在传统的servlet 容器中工作,也不能构建成 war 包。
Spring Cloud Gateway 旨在为微服务架构提供一种简单且有效的 API 路由的管理方式,并基于 Filter 的方式提供网关的基本功能,例如说安全认证、监控、限流等等。
其它网关组件:
在 SpringCloud 微服务体系中,有个很重要的组件就是网关,在 1.x 版本中都是采用的 Zuul 网关;但在2.x版本中,zuul 的升级一直跳票,SpringCloud 最后自 己研发了一个网关替代 Zuul,那就是SpringCloud Gateway
网上很多地方都说 Zuul 是阻塞的,Gateway是非阻塞的,这么说是不严谨的,准确的讲 zuul 1.x 是阻塞的,而在 2.x 的版本中,Zuul 也是基于 Netty,也是非阻塞的,如果一定要说性能,其实没多大差距。
Spring Cloud Gateway 功能特征
- 基于Spring Framework 5,Project Reactor 和 Spring Boot 2.0 进行构建;
- 动态路由:能够匹配任何请求属性;
- 支持路径重写;
- 集成Spring Cloud服务发现功能(Nacos、 Eruka);
- 可集成流控降级功能(Sentinel、 Hystrix);
- 可以对路由指定易于编写的Predicate (断言)和Filter (过滤器);
1.1、核心概念
- 路由(route)
- 路由是网关中最基础的部分,路由信息包括一个ID、一个目的URI、一组断言工厂、一组 Filter 组成。如果断言为真,则说明请求的 URL 和配置的路由匹配。
- 断言(predicates)
- Java8 中的断言函数,SpringCloud Gateway 中的断言函数类型是 Spring5.0 框架中的ServerWebExchange。断言函数允许开发者去定义匹 Http request 中的任何信息,比如请求头和参数等。
- 过滤器(Filter)
- SpringCloud Gateway 中的 filter 分为 Gateway Fller 和 Global Filter。Fiter 可以对请求和响应进行处理。
二、Spring Cloud Gateway 快速开始
2.1、环境搭建
2.1.1、引入依赖
<!--gateway 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2.1.2、配置 application.yml 文件
现有两个服务,order(订单)和stock(库存)服务
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
# gateway 配置
gateway:
# 路由规则
routes:
# 路由唯一标识,路由到订单
- id: order_route
# 需要转发的地址
uri: http://localhost:8020
# 断言规则,用于路由规则的匹配
predicates:
- Path=/order-server/**
# http://localhost:8088/order-server/order/add 路由到
# http://localhost:8020/order-server/order/add
filters:
# 转发之前,去掉第一层的路径
# http://localhost:8020/order/add
- StripPrefix=1
#- id: stock_route
启动网关服务,请求http://localhost:8088/order-server/order/add
地址,可以看到路由到了订单服务,并且请求库存服务成功。
2.2、集成 Nacos
现在是在配置文件中写死了转发的路径地址
2.2.1、引入依赖
<!--nacos 服务注册与发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2.2.2、编写配置文件
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 192.168.33.62:8847
username: nacos
password: nacos
# gateway 配置
gateway:
# 路由规则
routes:
# 路由唯一标识,路由到订单
- id: order_route
# lb 指的是从 nacos 中按照名称获取微服务,并遵循负载均衡策略
uri: lb://order-server
# 断言规则,用于路由规则的匹配
predicates:
- Path=/order-server/**
filters:
- StripPrefix=1
可以看到 Nacos 注册中心的服务
此时请求接口http://localhost:8088/order-server/order/add
配置简写
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 192.168.33.62:8847
username: nacos
password: nacos
# gateway 配置
gateway:
discovery:
locator:
# 是否启动自动识别 nacos 服务
enabled: true
需要通过 nacos 中的服务名进行访问http://localhost:8088/order-server/order/add
三、Gateway 路由断言工厂(Route Predicate Factories)配置
作用:当请求 gateway 时候,使用断言对请求进行匹配,如果匹配成功就路由转发,匹配失败就返回 404。
3.1、内置路由断言工厂
SpringCloud Gateway 包括许多内置的断言工厂,所有这些断言都与 HTTP 请求的不同属性匹配。具体如下:
3.1.1、基于 Datetime 类型的断言工厂
此类型的断言,根据时间做判断,主要有三个:
AfterRoutePredicateFactory:接收一个日期参数,判断请求日期是否晚于指定日期
BeforeRoutePredicateFactory:接收一 个日期参数,判断请求日期是否早于指定日期
BetweenRoutePredicateFactory:接收两个日期参数,判断请求日期是否在指定时间段内
时间类型为 ZonedDateTime.now()
- After=2022-08-12T15:00:00.000+08:00[Asia/Shanghai]
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 192.168.33.62:8847
username: nacos
password: nacos
# gateway 配置
gateway:
# 路由规则
routes:
# 路由唯一标识,路由到订单
- id: order_route
# lb 指的是从 nacos 中按照名称获取微服务,并遵循负载均衡策略
uri: lb://order-server
# 断言规则,用于路由规则的匹配
predicates:
- Path=/order/**
- After=2022-08-12T15:00:00.000+08:00[Asia/Shanghai]
请求成功
修改时间为当前时间之前的时间后,访问接口为 404
3.1.2、基于远程地址的断言工厂
RemoteAddrRoutePredicateFactory:接收一个 IP 地址段,判断请求主机地址是否在地址段中。
- RemoteAddr=192.168.1.1/24
3.1.3、基于 Cookie 的断言工厂
CookieRoutePredicateFactory:接收两个参数,cookie 名字和一个正则表达式。判断请求 cookie 是否具有给定名称且值与正则表达式匹配
- Cookie=chocolate,ch.
3.1.4、基于 Header 的断言工厂
HeaderRoutePredicateFactory:接收两个参数,标题名称和正则表达式。判断请求 Header 是否具有给定名称且值与正则表达式匹配。
设置请求头中,X-Request-Id,必须为数字
- Header=X-Request-Id,\d+
使用 postman 进行测试
当请求头中没有X-Request-Id
或者值不为数字时,访问 404
3.1.5、基于 Host 的断言工厂
HostRoutePredicateFactory:接收一个参数,主机名模式。判断请求的 Host 是否满足匹配规则。
- Host=**.testhost.org
3.1.6、基于 Method 请求方法的断言工厂
MethodRoutePredicateFactory:接收一个参数,判断请求类型是否跟指定的类型匹配。
- Method=GET
当请求为 POST 请求时,404
3.1.7、基于 Path 请求路径的断言工厂
PathRoutePredicateFactory:接收一个参数,判断请求的 URI 部分是否满足路径规则。
# 效果类似于 url 中 /foo/xxx
- Path=/foo/{segment}
3.1.8、基于 Query 请求参数的断言工厂
QueryRoutePredicateFactory:接收两个参数,请求 param 和正则表达式,判断请求参数是否具有给定名称且值与正则表达式匹配。
# 效果类似于 url 中 ?baz=xxx
- Query=name,ba.
3.1.9、基于路由权重的断言工厂
WeightRoutePredicateFactory:接收一个[组名权重],然后对于同一个组内的路由按照权重转发
routes:
- id: weight_route1
uri: host1
predicates:
- Path=/order/**
- weitht=group3,1
- id: weight_route2
uri: host2
predicates:
- Path=/order/**
- Weight=group3,9
3.2、自定义路由断言工厂
自定义路由断言工厂需要继承 AbstractRoutePredicateFactory 类,重写 apply 方法的逻辑。在 apply 方法中可以通过 exchange.getRequest() 拿到 ServerHttpRequest 对象,从而可以获取到请求的参数、请求方式、请求头等信息。
注意:类命名必须以 RoutePredicateFactory 结尾
- 必须是 spring 组件 bean
- 类必须加上 RoutePredicateFactory 作为结尾
- 必须继承 AbstractRoutePredicateFactory
- 必须声明静态内部类,声明属性来接收配置文件中对应的断言信息
- 需要结合 shortcutFieldOrder 进行绑定
- 通过 apply 进行逻辑判断,true 就是匹配成功,false 匹配失败
实现效果为,当路由中有 hudu 字符串时,通过
@Component
public class CheckAuthRoutePredicateFactory extends AbstractRoutePredicateFactory<CheckAuthRoutePredicateFactory.Config> {
public CheckAuthRoutePredicateFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("name");
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange exchange) {
if (config.getName().equals("hudu")) {
return true;
}
return false;
}
};
}
/**
* 用于接收配置文件中 断言的信息
*/
@Validated
public static class Config {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
application.yml 配置
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 192.168.33.62:8847
username: nacos
password: nacos
# gateway 配置
gateway:
# 路由规则
routes:
# 路由唯一标识,路由到订单
- id: order_route
# lb 指的是从 nacos 中按照名称获取微服务,并遵循负载均衡策略
uri: lb://order-server
# 断言规则,用于路由规则的匹配
predicates:
- Path=/order/**
- CheckAuth=hudu
当 CheckAuth 不为 hudu 时,请求 404
四、过滤器工厂(GatewayFilter Factories)配置
Gateway 内置了很多的过滤器工厂,我们通过一些过滤器工厂可以进行一些业务逻辑处理器,比如添加剔除响应头,添加去除参数等
4.1、内置过滤器
4.1.1、添加请求头
spring:
# gateway 配置
gateway:
# 路由规则
routes:
# 路由唯一标识,路由到订单
- id: order_route
# lb 指的是从 nacos 中按照名称获取微服务,并遵循负载均衡策略
uri: lb://order-server
# 断言规则,用于路由规则的匹配
predicates:
- Path=/order/**
filters:
# 添加请求头
- AddRequestHeader=X-Request-color,red
@RequestMapping("/header")
public String header(@RequestHeader("X-Request-color") String color) {
return color;
}
4.1.2、添加请求参数
spring:
# gateway 配置
gateway:
# 路由规则
routes:
# 路由唯一标识,路由到订单
- id: order_route
# lb 指的是从 nacos 中按照名称获取微服务,并遵循负载均衡策略
uri: lb://order-server
# 断言规则,用于路由规则的匹配
predicates:
- Path=/order/**
filters:
# 添加请求参数
- AddRequestParameter=color,blue
@GetMapping("/parameter")
public String parameter(@RequestParam("color")String color) {
return color;
}
4.1.3、为匹配路由统一添加前缀
filters:
# 添加请求参数
- PrefixPath=/order-server
效果等同于在远处调用的服务上添加
server:
servlet:
context-path: order-server
请求接口http://localhost:8088/order/test
实际是转发到http://localhost:8088/order-server/order/test
4.1.4、重定向
filters:
# 重定向
- RedirectTo=302,https://www.baidu.com
请求接口http://localhost:8088/order/test
4.2、自定义过滤器工厂(局部过滤器)
继承 AbstractNameValueGatewayFilterFactory 且我们的自定义名称必须要以 GatewayFilterFactory 结尾并交给 spring 管理。
实现效果当请求接口中带有?name=hudu
时,才能请求成功
@Component
public class CheckAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<CheckAuthGatewayFilterFactory.Config> {
private static final Log log = LogFactory
.getLog(CheckAuthGatewayFilterFactory.class);
public CheckAuthGatewayFilterFactory() {
super(CheckAuthGatewayFilterFactory.Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("key","value");
}
@Override
public GatewayFilter apply(CheckAuthGatewayFilterFactory.Config config) {
return (exchange, chain) -> {
// 获取 key value 值
String key = exchange.getRequest().getQueryParams().getFirst(config.getKey());
// 如果 key value 等于对应的值 成功
if (StringUtils.hasText(key)) {
if (config.getValue().equals(key)) {
return chain.filter(exchange);
}
}
// 否则访问 404
exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
return exchange.getResponse().setComplete();
};
}
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;
}
}
}
filters:
- CheckAuth=name,hudu
4.3、全局过滤器(Global Filters)配置
局部过滤器和全局过滤器的区别:
局部过滤器:只针对某一个路由进行过滤,需要在路由中进行配置
全局过滤器:针对所有路由请求,一旦定义了就会投入使用
4.3.1、LoadBalancerClientFilter
LoadBalancerClientFilter 会查看 exchange 的属性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的值(一个 URI),如果该值的 scheme 是 lb,比如:lb://myserver,它会使用 SpringCloud 的 LoadBalancerClient 来将 myservice 解析成实际的 host 和 port,并替换掉 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的内容。
其实就是用来整合负载均衡 Ribbon 的
spring:
cloud:
gateway:
routes:
- id: order_route
uri: lb://mall-order
predicates:
- Path=/order/**
4.3.2、自定义全局过滤器
一般像授权,权限认证,日志记录等,会使用全局过滤器
@Component
public class MyGlobalFilter implements GlobalFilter {
Logger log = LoggerFactory.getLogger(this.getClass());
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info(exchange.getRequest().getPath().value());
return chain.filter(exchange);
}
}
如果既定义了局部过滤器,又定义了全局过滤器,会先经过局部过滤器,通过之后再经过全局过滤器
五、请求日志记录&跨域处理
5.1、Reactor Netty 访问日志
要启用 Reactor Netty 访问日志,需要设置-Dreactor.netty.http.server.accessLogEnabled=true
它必须是 Java 系统属性,而不是 Spring Boot 属性。
可以将日志记录为具有单独的访问日志文件。
logback.xml
<appender name="accessLog" class="ch.qos.logback.core.FileAppender">
<file>access_log.log</file>
<encoder>
<pattern>%msg%n</pattern>
</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>
六、Gateway 跨域配置(CORS Configuration)
通过 yml 配置方式
spring:
cloud:
gateway:
globalcors:
cors-configurations:
# 允许跨域访问的资源
'[/**]':
# 跨域允许来源
allowedOrigins: "*"
allowedMethods:
- GET
- POST
- DELETE
- PUT
- OPTOIN
通过 javaconfig 配置方式
@Configuration
public class SystemCorsFilter {
@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
// 允许的 method
corsConfiguration.addAllowedMethod("*");
// 允许的来源
corsConfiguration.addAllowedOrigin("*");
// 允许的请求头
corsConfiguration.addAllowedHeader("*");
//由于是通过 webflux 的方式,需要额外添加此配置
// 访问的资源
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**",corsConfiguration);
return new CorsWebFilter(source);
}
}
七、Gateway 整合 Sentinel 限流
网关作为内部系统外的一层屏障,对内起到一定的保护作用,限流便是其中之一。网关层的限流可以简单地针对不同路由进行限流,也可针对业务的接口进行限流,或者根据接口的特征分组限流。
- 添加依赖
<!--sentinel 整合 gateway-->
<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>
- 添加配置
# 配置 sentinel
sentinel:
transport:
dashboard: 127.0.0.1:8858
7.1、控制台实现方式
从1.6.0版本开始,Sentinel 提供了Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:
- route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeld
- 自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组
order-server 服务中提供如下服务
@RequestMapping("/hello")
public String hello() {
System.out.println("下单成功!");
return "Hello World ";
}
@RequestMapping("/flow")
public String flow() {
return "正常访问";
}
@RequestMapping("/flowThread")
public String flowThread() throws InterruptedException {
TimeUnit.SECONDS.sleep(2);
return "正常访问";
}
@RequestMapping("/get")
public String get() {
return "查询订单";
}
@RequestMapping("/err")
public String err() {
int i = 1 / 0;
return "hello";
}
@RequestMapping("/get/{id}")
public String getById(@PathVariable("id")Integer id) {
System.out.println("正常访问");
return "正常访问";
}
启动服务,可以看到 sentinel 已经为当前的路由生成了一个资源,设置流控 QPS 为 2,当请求网关频繁时,网关被流控了。
7.2、Gateway 整合 Sentinel 流控降级详细配置
7.2.1、Burst size:突发请求额外允许数
当一秒请求三次以上时,才会进行限流
7.2.2、针对断言工厂进行限流
精确:与设定的值相等
子串:模糊匹配
正则:正则表达式匹配
注意,localhost访问无效,需要通过 127.0.0.1 访问才行
针对请求头中的 X-Request-Id 的值进行限流
其它配置可以自行测试。
7.2.3、根据详细的地址分组流控
现在就可以根据 api 分组进行流控
7.2.4、降级
7.3、自定义降级返回信息
7.3.1、通过 yml
spring:
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8858
scg:
fallback:
mode: response
response-body: '{"code":403,"msg":"限流了"}'
7.3.2、通过 GatewayCallbackManager
@Configuration
public class GatewayConfig {
Logger log = LoggerFactory.getLogger(this.getClass());
@PostConstruct
public void init() {
BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
// 打印异常
log.error(throwable.getMessage());
HashMap<String, String> map = new HashMap<>();
map.put("code", HttpStatus.TOO_MANY_REQUESTS.toString());
if (throwable instanceof FlowException) {
map.put("msg", "接口限流了");
} else if (throwable instanceof DegradeException) {
map.put("msg", "服务降级了");
} else if (throwable instanceof ParamFlowException) {
map.put("msg", "热点参数限流了");
} else if (throwable instanceof SystemBlockException) {
map.put("msg", "触发系统保护规则了");
} else if (throwable instanceof AuthorityException) {
map.put("msg", "授权规则不通过");
}
// 自定义异常处理
return ServerResponse
// 响应状态码
.status(HttpStatus.OK)
// 响应类型
.contentType(MediaType.APPLICATION_JSON)
// 响应内容
.body(BodyInserters.fromValue(map));
}
};
GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}
}
7.4、代码实现方式(了解)
用户可以通过 GatewayRuleManage.loadRules(rules)手动加载网关规则
GatewayConfiguration 中添加
@Configuration
public class GatewayConfig {
Logger log = LoggerFactory.getLogger(this.getClass());
@PostConstruct
public void doInit() {
// 初始化自定义的 API
initCustomizedApis();
// 初始化网关限流规则
initGatewayRules();
// 自定义限流异常处理器
initBlockRequestHandler();
}
private void initCustomizedApis() {
HashSet<ApiDefinition> definitions = new HashSet<>();
ApiDefinition api = new ApiDefinition("user_service_api")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/user/**").setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
definitions.add(api);
GatewayApiDefinitionManager.loadApiDefinitions(definitions);
}
private void initGatewayRules() {
HashSet<GatewayFlowRule> rules = new HashSet<>();
// resource:资源名称,可以是网关中的 route 名称,或者是自定义的 API 分组名称
// count:限流阈值
// intervalSec:统计时间窗口,单位是 秒,默认是 1 秒
rules.add(new GatewayFlowRule("order_route")
.setCount(2)
.setIntervalSec(1));
rules.add(new GatewayFlowRule("user_service_api").setCount(2).setIntervalSec(1));
// 加载网关规则
GatewayRuleManager.loadRules(rules);
}
@PostConstruct
public void initBlockRequestHandler() {
BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
// 打印异常
log.error(throwable.getMessage());
HashMap<String, String> map = new HashMap<>();
map.put("code", HttpStatus.TOO_MANY_REQUESTS.toString());
if (throwable instanceof FlowException) {
map.put("msg", "接口限流了");
} else if (throwable instanceof DegradeException) {
map.put("msg", "服务降级了");
} else if (throwable instanceof ParamFlowException) {
map.put("msg", "热点参数限流了");
} else if (throwable instanceof SystemBlockException) {
map.put("msg", "触发系统保护规则了");
} else if (throwable instanceof AuthorityException) {
map.put("msg", "授权规则不通过");
}
// 自定义异常处理
return ServerResponse
// 响应状态码
.status(HttpStatus.OK)
// 响应类型
.contentType(MediaType.APPLICATION_JSON)
// 响应内容
.body(BodyInserters.fromValue(map));
}
};
GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}
}
八、Gateway 网关高可用
为了保证 Gateway 的高可用性,可以同时启动多个 Gateway 实例进行负载,在 Gateway 的上游使用Nginx 或者 F5 进行负载转发以达到高可用。