一、前言
之前我们说断言规则的时候,在进行调用的过程中出现了 trace 报错。
但是默认的话是返回的一个 HTML 页面,这对于我们前后端分离式开发是没有用的,我们需要的是返回给前段一段错误 JSON 信息。
有的人可能会问了,SpringBoot 中不是给我们带了一个 @ControllerAdvice 的注解进行配置异常信息返回吗,为啥还要在 Gateway 中进行全局异常配置?
来看这个图,如果我们在服务层进行逻辑处理,或者是和数据库进行操作的时候报错了,我们是可以通过 @ControllerAdvice 注解所配置的异常处理进行返回。但是!!!
如果我们的服务是在 Gateway 进行请求的时候发生了错误呢?好比之前我们的 404 没有找到服务,那么我们的 @ControllerAdvice 是没有办法捕获到错误进行处理的,所以我们可以在所有微服务上层也就是 Gateway 中进行统一配置。
二、Gateway 全局异常配置
首先去创建一个 GatewayExceptionHandler 类,这个类需要实现 ErrorWebExceptionHandler 接口。ErrorWebExceptionHandler 接口是 Gateway 最核心接口,所以我们实现这个接口即可。
@Order(-1)
@Configuration
public class GatewayExceptionHandler implements ErrorWebExceptionHandler {
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
ServerHttpResponse response = exchange.getResponse();
if(response.isCommitted()) {
return Mono.error(ex);
}
String msg;
if (ex instanceof NotFoundException) {
msg = "服务未找到";
} else if (ex instanceof ResponseStatusException) {
ResponseStatusException responseStatusException = (ResponseStatusException) ex;
msg = responseStatusException.getMessage();
} else {
msg = "内部服务器错误";
}
return ServletUtil.webFluxResponseWriter(response, msg);
}
}
简单解释一下代码~~~
首先是第一个判断,如果是 response 已经提交响应了,那么我们是直接返回 Mono 的错误信息。如果没有提交,我们就去看这个错误信息是什么,将错误信息赋值给 msg 对象,并且使用 webFluxResponseWriter 写回客户端即可。
接着再来一个工具类。
public class ServletUtil {
/**
* 设置webflux模型响应
*
* @param response ServerHttpResponse
* @param value 响应内容
* @return Mono<Void>
*/
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, String value) {
return webFluxResponseWriter(response, HttpStatus.OK, value, 500);
}
/**
* 设置webflux模型响应
*
* @param response ServerHttpResponse
* @param code 响应状态码
* @param value 响应内容
* @return Mono<Void>
*/
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, String value, int code) {
return webFluxResponseWriter(response, HttpStatus.OK, value, code);
}
/**
* 设置webflux模型响应
*
* @param response ServerHttpResponse
* @param status http状态码
* @param code 响应状态码
* @param value 响应内容
* @return Mono<Void>
*/
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, HttpStatus status, String value, int code) {
return webFluxResponseWriter(response, MediaType.APPLICATION_JSON_VALUE, status, value, code);
}
/**
* 设置webflux模型响应
*
* @param response ServerHttpResponse
* @param contentType content-type
* @param status http状态码
* @param code 响应状态码
* @param value 响应内容
* @return Mono<Void>
*/
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, String contentType, HttpStatus status, String value, int code) {
response.setStatusCode(status);
response.getHeaders().add(HttpHeaders.CONTENT_TYPE, contentType);
String result = ResultUtil.resultToString(Result.error(value));
DataBuffer dataBuffer = response.bufferFactory().wrap(result.getBytes());
return response.writeWith(Mono.just(dataBuffer));
}
工具类比较简单,就是将错误信息写出去。(Result 这个类,自己去弄,实在不行就自己弄个 Map 对象去用)。
写好之后其实我们可以测试一下。
我这里测试是使用 Weight 权重断言模式下进行测试的,可以使用 After、Before、Between 模式测试 404 之类的。
三、WebFlux 响应式编程
上面工具类中我们配置了一个东西:Webflux 模型响应。这里我们来简单介绍一下这是什么玩意。
1. Webflux
Webflux,它是 Spring 5.0 中发布的一个重量级组件,并拉起了响应式编程的规模使用序幕。
我们最开始使用的是 Spring MVC 这种同步阻塞式的调用,但是这种请求模式是有着很大的弊端,就是没有太大的吞吐量,而这也就意味着用户需要等待~~~
而 Webflux 的推出,使得这个问题有了很大的改善。
该组件是异步非阻塞的,使用 Webflux 作为系统解决方案,在大多数场景下可以提高系统吞吐量。
注意!Webflux 的出现,并不是替代之前的 Spring MVC,而是各有各的作用,相互不影响。
2. 响应式编程
我们通过一个简单的 Java 代码来讲述什么是响应式编程。
public static void main(String[] args) {
int a = 1;
int b = 2;
int c = a + b;
System.out.println(c);
}
代码很简单,声明变量 a、b、c,最后输出 c 的值,c 是 3。当然这个没有啥可以说的,好比我们在定义 c 之后,操作 b 的值,那么 c 还会变吗?
答案是:不会变。
上面的这个案例其实就是我们经常写的命令式编程,但如果上面的代码是响应式编程的,那么最后输出的 c 不是 3,而是 4。
在计算机中,响应式编程或反应式编程(英语:Reactive programming)是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。
响应式编程是基于异步和事件驱动的非阻塞程序,只需要在程序内启动少量线程扩展,而不是水平通过集群扩展。
用大白话讲,我们以前编写的大部分都是阻塞类的程序,当一个请求过来时任务会被阻塞,直到这个任务完成后再返回给前端;响应式编程接到请求后只是提交了一个请求给后端,后端会再安排另外的线程去执行任务,当任务执行完成后再异步通知到前端。
3. Reactor
说到响应式编程,就必须要提一个东西,Reactor!
Reactor 是一个基于 JVM 之上的异步应用基础库,为 Java 、Groovy 和其他 JVM 语言提供了构建基于事件和数据驱动应用的抽象库。而且正如它的名称一样,它在最新的硬件平台上,使用无堵塞分发器每秒钟可处理 1500 万个事件。
Reactor 中有两个非常重要的东西,Flux 和 Mono。
4. Flux 和 Mono
Reactor 中的发布者(Publisher)由 Flux 和 Mono 两个类定义,它们都提供了丰富的操作符(operator)。
一个 Flux 对象代表一个包含 0…N 个元素的响应式序列,而一个 Mono 对象代表一个包含零/一个(0…1)元素的结果。
既然是“数据流”的发布者,Flux和Mono都可以发出三种“数据信号”:元素值、错误信号、完成信号。
错误信号和完成信号都是终止信号,完成信号用于告知下游订阅者该数据流正常结束,错误信号终止数据流的同时将错误传递给下游订阅者。
当然,这个东西比较复杂,能理解就理解,理解不了就慢慢去理解好了,推荐是找几本书看。
这一讲就讲到这里,有问题可以联系我:QQ 2100363119,欢迎大家访问我的个人网站:https://www.lemon1234.com
Gateway 全局配置是参考的若依代码,感谢若依开源~