在平常的springboot项目中,我们通常会定义一个全局异常处理的Handler,返回自定义的的json格式:
import cn.wjp.common.system.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 全局异常捕捉处理
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(value = Exception.class)
public Result errorHandler(Exception e) {
e.printStackTrace();//便于调试
return Result.getFailedResultFromException(e);
}
}
从异常中获取错误信息的工具类:
import cn.wjp.common.system.exception.BusinessException;
import cn.wjp.common.system.exception.ErrorMsg;
import cn.wjp.common.system.utils.ExceptionUtil;
import java.io.Serializable;
@Getter
@Setter
public class Result<T> implements Serializable {
/**
* 错误码.
*/
private String code;
/**
* 提示信息.
*/
private String msg;
/**
* 具体的内容.
*/
private T data;
public static Result getFailedResultFromException(Exception e) {
Result r = new Result();
String errMessage = e.getMessage()==null?"":e.getMessage();
//如果是自定义异常,把状态码返回给前端,便于区分不同的错误
if(e instanceof BusinessException){
BusinessException exception =(BusinessException)e;
String code = exception.getCode();
r.setCode(code);
r.setMsg(exception.getMsg());
}else{//否则,当作一般性的错误,状态码是固定的
r.setCode(ErrorMsg.ERROR.getCode()+"");
r.setMsg(ErrorMsg.ERROR.getMsg()+","+errMessage);
}
r.setData(ExceptionUtil.getStackTrace(e));
return r;
}
}
import java.io.PrintWriter;
import java.io.StringWriter;
public class ExceptionUtil {
/**
* 获取异常堆栈信息
* @param throwable
* @return
*/
public static String getStackTrace(Throwable throwable) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
try {
throwable.printStackTrace(pw);
return sw.toString();
} finally {
pw.close();
}
}
}
如果是在springcloud项目中呢,我们如何处理全局异常,我的一个办法是继续在每个服务模块中写上述的全局异常处理代码(通过编写公共模块,引入pom即可),在此基础上,可以在zuul上定义过滤器,处理全局异常:
import com.alibaba.fastjson.JSON;
import cn.wjp.common.system.Result;
import com.netflix.zuul.context.RequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import javax.servlet.http.HttpServletResponse;
/**
* 重写错误过滤器 使它返回标准的格式
*/
@Component
public class ErrorFilter extends SendErrorFilter {
private final static Logger logger = LoggerFactory.getLogger(ErrorFilter.class);
@Override
public Object run() {
try{
RequestContext ctx = RequestContext.getCurrentContext();
//直接复用异常处理类
Throwable throwable = ctx.getThrowable();
ExceptionHolder exceptionHolder = findZuulException(throwable);
Exception exception = null;
if(throwable instanceof Exception){
exception = (Exception)throwable.getCause();
}
logger.info("异常信息:{}", throwable);
Result result;
if(exception!=null){
result = Result.getFailedResultFromException(exception);
}else{
result = Result.getFailedResult(exceptionHolder.getErrorCause());
}
HttpServletResponse response = ctx.getResponse();
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(JSON.toJSONString(result));
}catch (Exception ex) {
ReflectionUtils.rethrowRuntimeException(ex);
}
return null;
}
}
这样不论后台报什么错,都能返回我们想要的格式。不足的一点就是,当服务不可用或者正在启动,当你访问该服务模块的时候,会返回自定义json,但是我们却无法得知到底出了什么问题,都是统一的forwardException,表示在网关处转发请求失败。