You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Spring的HttpMessageNotReadableException中获取原始请求体?

如何在HttpMessageNotReadableException中获取原始请求体

直接通过HttpMessageNotReadableException.getHttpInputMessage().getBody()无法拿到原始请求体,原因是Spring在解析请求体时已经将InputStream的字节读取完毕,且该流通常不支持mark/reset功能,无法重复读取。

要解决这个问题,需要提前缓存请求体,可通过自定义过滤器结合ContentCachingRequestWrapper实现:

1. 编写请求缓存过滤器

将原始请求包装为ContentCachingRequestWrapper,它会自动缓存请求体内容:

@Component
public class RequestCachingFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 仅针对带请求体的HTTP方法做缓存
        if (HttpMethod.POST.name().equals(request.getMethod()) || HttpMethod.PUT.name().equals(request.getMethod())) {
            ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
            filterChain.doFilter(wrappedRequest, response);
        } else {
            filterChain.doFilter(request, response);
        }
    }
}

2. 在异常处理器中读取缓存的请求体

在异常处理方法中注入HttpServletRequest,判断其是否为包装后的实例,再读取缓存内容:

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(HttpMessageNotReadableException.class)
public GenericErrorResp exceptionHandler(HttpMessageNotReadableException e, HttpServletRequest request) {
    if (request instanceof ContentCachingRequestWrapper) {
        ContentCachingRequestWrapper wrappedRequest = (ContentCachingRequestWrapper) request;
        byte[] cachedBody = wrappedRequest.getContentAsByteArray();
        if (cachedBody.length > 0) {
            String rawBody = new String(cachedBody, request.getCharacterEncoding());
            log.error("Invalid request body: {}", rawBody, e);
        } else {
            log.error("Invalid body (empty or not cached)", e);
        }
    } else {
        log.error("Invalid body (request not wrapped)", e);
    }
    return new GenericErrorResp();
}

注意事项

  • ContentCachingRequestWrapper会将请求体缓存到内存中,对于超大请求体可能造成内存压力,建议根据业务场景限制请求体大小,或添加相应判断逻辑。
  • 过滤器需确保在Spring请求体解析前执行,使用@Component注解的过滤器默认会在Spring MVC核心过滤器之前生效,无需额外配置。

内容的提问来源于stack exchange,提问作者Rubén Aguado

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 00:45:35