前言
网关作为我们对外服务的入口起着至关重要的作用,我们必须保证网关服务的稳定性,下面来为网关服务增加异常处理机制。
一、异常处理
1. 响应实体类
package org.example.common.model;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
//统一响应结果
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
private Integer code;//业务状态码 0-成功 1-失败
private String title;//标题
private String message;//提示信息
private T data;//响应数据
public Result(Integer code, String title, String message) {
this.code = code;
this.title = title;
this.message = message;
}
public Result(Integer code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
//快速返回操作成功响应结果(带响应数据)
public static <E> Result<E> success(E data) {
return new Result<>(0, "操作成功", data);
}
public static <E> Result<E> success(String message,E data) {
return new Result<>(0, message, data);
}
public static Result success(String message) {
return new Result<>(0, message, null);
}
//快速返回操作成功响应结果
public static Result success() {
return new Result(0, "操作成功", null);
}
public static Result error(String message) {
return new Result(1, message, null);
}
public static Result error(int code,String message) {
return new Result(code, message, null);
}
public static Result error(int code,String title,String message) {
return new Result(code,title , message);
}
}
2. 异常处理类
这里针对性地处理了无可用路由和无可用服务两种场景异常,和一种铺地异常的处理,大家有自定义异常或其他异常可自行添加处理逻辑
package org.example.gateway.config;
import org.example.common.model.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.reactive.resource.NoResourceFoundException;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* Create by zjg on 2024/7/27
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(NoResourceFoundException.class)//无可用路由
public Result exception(ServerHttpResponse response,NoResourceFoundException ex){
String detail = ex.getBody().getDetail();
String mark="resource ";
String message = detail.substring(detail.indexOf(mark) + mark.length());
setStatusCode(response,ex.getStatusCode());
return Result.error(ex.getStatusCode().value(),"无可用路由",String.format("没有可用的路由[%s]",message));
}
@ExceptionHandler(NotFoundException.class)//无可用服务
public Result exception(ServerHttpResponse response,NotFoundException ex){
logger.error(ex.getMessage());
String detail = ex.getBody().getDetail();
String mark="for ";
String message = detail.substring(detail.indexOf(mark) + mark.length());
setStatusCode(response,ex.getStatusCode());
return Result.error(ex.getStatusCode().value(),"服务不可用",String.format("没有可用的服务实例[%s]",message));
}
@ExceptionHandler(Exception.class)//异常保底
public Result exception(ServerHttpResponse response,Exception exception){
StringWriter stringWriter = new StringWriter();
PrintWriter writer=new PrintWriter(stringWriter);
exception.printStackTrace(writer);
logger.error(stringWriter.toString());
setStatusCode(response,HttpStatus.INTERNAL_SERVER_ERROR);
return Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(),exception.getMessage());
}
private void setStatusCode(ServerHttpResponse response,HttpStatusCode httpStatusCode){
response.setStatusCode(httpStatusCode);
}
}
二、单元测试
1. 无可用路由
curl 192.168.0.104:8888/provider/hello -H "Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGFpbXMiOnsidXNlcm5hbWUiOiJhZG1pbiJ9LCJpc3MiOiJhdXRoMCIsImV4cCI6MTcyMjE0NjE0MX0.IRlUZ5H_-PbPSbklqFGB1lOYquj0iifV2mhT-z68fhM"