SpringBoot 解决request请求体只能被读一次的问题,在全局异常@RestControllerAdvice ExceptionHandler中打印参数

得意时要看淡,失意时要看开。不论得意失意,切莫大意;不论成功失败,切莫止步。志得意满时,需要的是淡然,给自己留一条退路;失意落魄时,需要的是泰然,给自己觅一条出路SpringBoot 解决request请求体只能被读一次的问题,在全局异常@RestControllerAdvice ExceptionHandler中打印参数,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

背景: request.getInputStream()获取请求body里面的内容只能被获取一次,ContentCachingRequestWrapper通过这个类能够解决解决HttpServletRequest inputStream只能读取一次的问题,但是这个类有缺陷(前提必须是doFilter之前不能使用request.getInputStream()方法)

使用场景:
全局异常捕获类中打印异常POST请求的参数。

步骤一: 创建Filter

public class CachingContentFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        if (request instanceof HttpServletRequest) {
            if (request.getContentType() != null && !request.getContentType().contains(MediaType.MULTIPART_FORM_DATA_VALUE)) {
                ContentCachingRequestWrapper wrapper = new ContentCachingRequestWrapper((HttpServletRequest) request);
                //测试
                String requestBody = getRequestBody(wrapper);
                System.out.println("repeat:" + requestBody);
                chain.doFilter(wrapper, response);
                return;
            }
        }
        chain.doFilter(request, response);
    }
    private String getRequestBody(HttpServletRequest request) {
        String requestBody = "";
        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if (wrapper != null) {
            try {
                requestBody = IOUtils.toString(wrapper.getContentAsByteArray(), wrapper.getCharacterEncoding());
            } catch (IOException e) {
            }
        }
        return requestBody;
    }
}

步骤2: 在全局异常捕获类中使用

@RestControllerAdvice
public class ServiceExceptionHandler {
	/** logger */
    private static final Logger LOGGER = LoggerFactory.getLogger(ServiceExceptionHandler.class);
    
    /**
     * 捕获ServiceException
     *
     * @param e
     * @return
     */
    @ExceptionHandler({com.cl.exam.core.exception.ServiceException.class})
    @ResponseStatus(HttpStatus.OK)
    public ApiRest serviceExceptionHandler(HttpServletRequest req, ServiceException e) {
        LOGGER.error("服务异常!",e);
        printLog(req)
        return new ApiRest(e);
    }

    private void printLog(HttpServletRequest req) {
        LOGGER.error("RequestInfo:uri={}, method={}, params={}, body={}",
                req.getRequestURI(),
                req.getMethod(),
                req.getParameterMap(),
                getRequestBody(req));
    }

    private String getRequestBody(HttpServletRequest request) {
        String requestBody = "";
        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if (wrapper != null) {
            try {
                requestBody = IOUtils.toString(wrapper.getContentAsByteArray(), wrapper.getCharacterEncoding());
            } catch (IOException e) {
            }
        }
        return requestBody;
    }
}

注意事项
该类的使用必须在执行到了Controller层,才能通过缓存获取请求体,通过查看源码实现可以发现,实际缓存请求内容的步骤是在读取request.inputStrem的时候进行的缓存(ContentCachingInputStream的read方法中)。
所以只有请求被实际消费了,才能通过ContentCachingRequestWrappergetContentAsByteArray方法获取到请求体,否则是空的。

解决办法:
1、重写ContentCachingRequestWrapper,增加手动缓存方法。不推荐
2、对Controller层进行aop

参考文章:
https://blog.csdn.net/u013887008/article/details/128338085

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/155932.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!