spring全局异常处理类ExceptionHandler获取request入参

背景

项目中需要用到的数据校验、异常捕获,所以会用@ExceptionHandler方法,对Controller做统一的全局异常处理。当发生异常时,需要记录异常的url、入参、出参、错误信息等。但是request的inputStream已经读取过一次,此时拿到的request是空的。

解决方法

Spring提供了一个ContentCachingRequestWrapper,用于缓存从输入流读取出来的内容。我们可以在过滤器(Filter)中,将HttpServletRequest包装成ContentCachingRequestWrapper,这样后续就可以重复获取到请求体内容了。

定义RequestWrapperFilter

@Component
public class RequestWrapperFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        filterChain.doFilter(new ContentCachingRequestWrapper(httpServletRequest), httpServletResponse);
    }
}

修改GlobalExceptionHandler

@Slf4j
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
    public static final String SERVICE_EXCEPTION = "order_exception";
    /**
     * 声明要捕获的异常
     */
    @ExceptionHandler({BindException.class,
            MethodArgumentNotValidException.class,
            GlobalException.class,
            Exception.class})
    @ResponseBody
    public <T> BaseResponse<T> handleException(Exception e) {
        BaseResponse<T> baseResponse;
        if (e instanceof BindException) {
            baseResponse = handle(((BindException) e).getBindingResult());
        } else if (e instanceof MethodArgumentNotValidException) {
            baseResponse = handle(((MethodArgumentNotValidException) e).getBindingResult());
        } else if (e instanceof GlobalException) {
            HttpError httpError = ((GlobalException) e).getHttpError();
            baseResponse = ResponseUtils.fail(httpError.getCode(), httpError.getMessage());
        } else {
            baseResponse = ResponseUtils.fail(OrderHtapResultEnum.SYSTEM_ERROR.getCode(), "系统异常:" + e);
        }
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        log.error("handleException catch exception!url:{},request:{},response:{},error:{}", request.getRequestURI(), JSON.toJSONString(getRequestBody(request)), baseResponse, e);
        MetricsApi.getInstance().reportCounter(SERVICE_EXCEPTION, 1);
        return baseResponse;
    }
    //重点是这里
    private static String getRequestBody(HttpServletRequest request) {
        ContentCachingRequestWrapper requestWrapper =
                WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if (requestWrapper == null) {
            return "";
        }
        return new String(requestWrapper.getContentAsByteArray(), StandardCharsets.UTF_8);
    }


    private <T> BaseResponse<T> handle(BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            log.error("verifyParams error --> " + bindingResult.toString());
            FieldError fieldError = bindingResult.getFieldError();
            return ResponseUtils.fail(OrderHtapResultEnum.PARAM_ERROR.getCode(), OrderHtapResultEnum.PARAM_ERROR.getMessage() + "(" + fieldError.getField() + ":" + fieldError.getDefaultMessage() + ")");
        }
        return ResponseUtils.fail(OrderHtapResultEnum.PARAM_ERROR.getCode(), OrderHtapResultEnum.PARAM_ERROR.getMessage());
    }
}

这里只适合post,put调用的方法,get调用的获取不到。

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值