Spring Cloud 架构设计之全局异常处理及Feign异常传递

Spring Cloud 架构设计之全局异常处理

前言

近期,本人在开发一款互联网产品,项目地址https://github.com/yjjhkyq/doubi。同时,我也将通过连载的方式,将这款互联网产品的架构、技术细节等逐步记录下来,欢迎大家指正。

一、异常定义

public class ApiException extends RuntimeException
{
    private static final long serialVersionUID = 1L;

    private long code;

    private String message;

    public ApiException(String message)
    {
        this.message = message;
    }

    public ApiException(String message, long code)
    {
        this.message = message;
        this.code = code;
    }

    public ApiException(long code, String message)
    {
        this.message = message;
        this.code = code;
    }

    public ApiException(IErrorCode errorCode){
        this.code = errorCode.getCode();
        this.message = errorCode.getMessage();
    }

    public ApiException(String message, Throwable e)
    {
        super(message, e);
        this.message = message;
    }

    @Override
    public String getMessage()
    {
        return message;
    }

    public long getCode()
    {
        return code;
    }
}

当然,你还可以根据项目实际情况定义其他异常信息

二、全局捕获异常

、
@RestControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    /**
     * 请求方式不支持
     */
    @ExceptionHandler({ HttpRequestMethodNotSupportedException.class })
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R handleException(HttpRequestMethodNotSupportedException e)
    {
        log.error(e.getMessage(), e);
        return R.fail("not support' " + e.getMethod() + "'req");
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R notFount(RuntimeException e)
    {
        log.error("server errror:", e);
        return R.fail("server errror:" + e.getMessage());
    }

    /**
     * 系统异常
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R handleException(Exception e)
    {
        log.error(e.getMessage(), e);
        return R.fail("server errror");
    }

    /**
     * 业务异常
     */
    @ExceptionHandler(ApiFeignException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R businessException(ApiFeignException e)
    {
        log.error("api feign exception {} {}", e.getCode(), e.getMessage());
        return R.build(e.getCode(), e.getMessage());
    }

    /**
     * 业务异常
     */
    @ExceptionHandler(ApiException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R businessException(ApiException e)
    {
        log.error("api exception {} {}", e.getCode(), e.getMessage());
        return R.build(e.getCode(), e.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
    {
        List<ObjectError> errors =e.getBindingResult().getAllErrors();
        StringBuffer errorMsg=new StringBuffer();
        errors.stream().forEach(x -> errorMsg.append(x.getDefaultMessage()).append(";"));
        return R.build(ResultCode.VALIDATE_FAILED, errors);
    }
}

出现异常后,代码中通过@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)将HTTP状态码设置为500,这样设置有如下意义:

  • 如果是直接返回给前端,则明确告诉前端服务器出现了错误
  • 以便Feign的ErrorDecoder能够捕获,见下一章节

三 Feign异常传递:ErrorDecoder

在实际应用中,当通过Feign进行RPC调用的时候,如果上游的服务出现了异常,这时候我们希望在调用端能够通过try catch的方式捕获到,或者直接将异常传递给前端,怎么做呢,实现ErrorDecoder:

@Slf4j
@Configuration
public class FeignErrorDecoder implements ErrorDecoder {

    @Override
    public Exception decode(String s, Response response) {
        log.error("feign error, request url:{} status:{}", response.request().toString(), response.status());
        try {
            if (response.status() == HttpStatus.INTERNAL_SERVER_ERROR.value()){
                String body = IOUtils.toString(response.body().asReader(StandardCharsets.UTF_8));;
                return JsonUtil.parseObject(body, ApiException.class);
            }
            return errorStatus(s, response);
        }
        catch (Exception e){
            return e;
        }
    }
}

总结

写完了,弱弱的问下,可以帮我的开源项目点个赞码?

你可能感兴趣的:(基于微服务开发一款互联网产品,spring,cloud,java,微服务)