侧边栏壁纸

🌩️ Spring Cloud Gateway中的全局异常处理

2024年10月26日 221阅读 0评论 0点赞

1️⃣ 异常处理器的配置

在这次的异常处理中,我实现了一个类为 GatewayExceptionHandler 的全局异常处理器,它使用了 ErrorWebExceptionHandler 接口来对经过网关的请求进行应对的异常处理。

为了便于网关的应用,我为此类添加了 @Component 模式,使得它能被实例化并当作应用程序的 Bean 被引用。

🔍 代码解析

类代码如下:

package com.jingdianjichi.club.gateway.exception;

import cn.dev33.satoken.exception.SaTokenException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jingdianjichi.club.gateway.entity.Result;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@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) {
            code = 401; // 无权限
            message = "用户无权限";
        } else {
            code = 500; // 系统错误
            message = "系统繁忙";
        }

        // 创建返回结果对象
        Result result = Result.fail(code, message);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);

        // 将返回的结果转换为JSON格式并写入响应
        return response.writeWith(Mono.fromSupplier(() -> {
            DataBufferFactory dataBufferFactory = response.bufferFactory();
            byte[] bytes = null;
            try {
                bytes = objectMapper.writeValueAsBytes(result);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            return dataBufferFactory.wrap(bytes);
        }));
    }
}

🚀 代码讲解

  1. ServerHttpRequestServerHttpResponse:获取请求和响应对象,方便后续处理。
  2. 异常类型判断:通过 instanceof 来判断是否是 SaTokenException,如果是,就返回401,表示“用户无权限”,否则返回500,表示“系统繁忙”。
  3. 返回结果封装:使用 Result 类来封装返回结果,使返回格式统一。
  4. 设置响应格式为 JSON:通过 response.getHeaders().setContentType(MediaType.APPLICATION_JSON) 设置返回类型为 JSON。
  5. 写入响应:将结果转换为字节并写入响应中。

2️⃣ Result类的实现

为了方便统一返回的结果信息,我设计了一个全局的 Result 类用于表示结果。

🔍 代码解析

代码如下:

package com.jingdianjichi.club.gateway.entity;

import com.jingdianjichi.club.gateway.ResultCodeEnum;
import lombok.Data;

@Data
public class Result<T> {

    private Boolean success; // 是否成功
    private Integer code;    // 返回码
    private String message;  // 返回信息
    private T data;          // 返回的数据内容

    // 创建一个失败的结果对象,附带数据
    public static <T> Result fail(T data) {
        Result result = new Result();
        result.setSuccess(false);
        result.setCode(ResultCodeEnum.FAIL.getCode());
        result.setMessage(ResultCodeEnum.FAIL.desc);
        result.setData(data);
        return result;
    }

    // 创建一个通用的失败结果对象
    public static Result fail() {
        Result result = new Result();
        result.setSuccess(false);
        result.setCode(ResultCodeEnum.FAIL.getCode());
        result.setMessage(ResultCodeEnum.FAIL.desc);
        return result;
    }

    // 创建一个成功的结果对象,附带数据
    public static <T> Result ok(T data) {
        Result result = new Result();
        result.setSuccess(true);
        result.setCode(ResultCodeEnum.SUCCESS.getCode());
        result.setMessage(ResultCodeEnum.SUCCESS.getDesc());
        result.setData(data);
        return result;
    }

    // 创建一个通用的成功结果对象
    public static Result ok() {
        Result result = new Result();
        result.setSuccess(true);
        result.setCode(ResultCodeEnum.SUCCESS.getCode());
        result.setMessage(ResultCodeEnum.SUCCESS.desc);
        return result;
    }

    // 创建一个自定义错误信息的失败结果对象
    public static Result fail(Integer code, String message) {
        Result result = new Result();
        result.setSuccess(false);
        result.setCode(code);
        result.setMessage(message);
        return result;
    }
}

🚀 代码讲解

  1. success:表示操作是否成功的布尔值。
  2. codemessage:用于描述操作结果的状态码和信息。
  3. 静态方法 okfail:提供便捷的方法来生成不同的返回结果,便于在代码中使用。

3️⃣ 结果码枚举的设计

为了统一结果码的管理,我使用了一个结果码的枚举类 ResultCodeEnum,以统一返回码和应对的描述。

🔍 代码解析

代码如下:

package com.jingdianjichi.club.gateway;

import lombok.Getter;

@Getter
public enum ResultCodeEnum {

    SUCCESS(200, "成功"),
    FAIL(500, "失败");

    // 状态码
    public int code;

    // 描述
    public String desc;

    ResultCodeEnum(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    /**
     * 根据状态码获取枚举
     */
    public static ResultCodeEnum getByCode(int codeVal) {
        for (ResultCodeEnum resultCodeEnum : ResultCodeEnum.values()) {
            if (resultCodeEnum.code == codeVal) {
                return resultCodeEnum;
            }
        }
        return null;
    }
}

🚀 代码讲解

  1. SUCCESSFAIL:定义了两种常见的结果码,分别表示成功和失败。
  2. getByCode 方法:根据状态码获取对应的枚举值,便于使用。
0
打赏

—— 评论区 ——

昵称
邮箱
网址
取消
人生倒计时
舔狗日记