Gateway实现全局异常处理

270 阅读2分钟
@Component
public class GatewayExceptionHandler implements ErrorWebExceptionHandler {

    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public Mono<Void> handle(ServerWebExchange serverWebExchange, Throwable throwable) {
        ServerHttpRequest request = serverWebExchange.getRequest();
        ServerHttpResponse response = serverWebExchange.getResponse();

        Integer code = 200;
        String message = "";
        if(throwable instanceof SaTokenException) { //如果异常对象为SaTokenException的实现类
            code = 401;   //和登录、无权限等相关的错误返回用户无权限
            message = "用户无权限";
        } else {
            code = 500; // 限流、熔断降级等错误返回系统繁忙
            message = "系统繁忙";
        }
        Result fail = Result.fail(code, message);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON); //设置客户端返回的响应体数据格式是JSON
        return response.writeWith(Mono.fromSupplier(new Supplier<DataBuffer>() {
            @Override
            public DataBuffer get() {
                DataBufferFactory dataBufferFactory = response.bufferFactory();
                byte[] bytes = null;
                try {
                    bytes = objectMapper.writeValueAsBytes(fail);
                } catch (JsonProcessingException e) {
                    throw new RuntimeException(e);
                }
                return dataBufferFactory.wrap(bytes);
            }
        }));

代码解读:

  • response.writeWith:方法是 Spring WebFlux 中用于将给定的 Publisher(发布者,在响应式编程中用于异步提供数据)中的数据写入到服务器响应体的方法。这里传入的参数是一个 Mono,Mono 是一种特殊的 Publisher,表示它最多只发布一个元素(在这个场景下,就是包含错误信息的 DataBuffer),非常适合用于返回单个响应体这种情况。

  • Mono.fromSupplier:方法接受一个 Supplier 接口的实现作为参数,并基于此创建一个 Mono。Supplier 接口是一个函数式接口,它定义了一个无参的 get 方法,用于提供一个值(在这里就是要返回一个 DataBuffer 对象)。

  • Supplier《DataBuffer》: 代表我们要获取一个DataBuffer对象,在匿名内部类中首先要创建DataBufferFactory工厂,用于创建DataBuffer对象(DataBuffer是响应体数据) 不同的实现可能对应不同的底层存储机制(比如内存、堆外内存等),而 DataBufferFactory 则提供了统一的创建方式来适配这些不同的场景。

  • objectMapper:是Jackson位于Jackson包下,用于 JSON 序列化和反序列化。此处将fail信息转为byte数组。

  • dataBufferFactory.wrap:方法是将字节数组 bytes 包装成一个 DataBuffer 对象。

此外,还需将全局过滤器中的异常处理删除,否则会覆盖全局异常处理

image.png