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

Spring MVC(非Spring Boot)拦截任意HTTP请求并提取请求体方案

Great question! The limitation you're hitting with ContentCachingRequestWrapper in a HandlerInterceptor boils down to two key issues: first, HandlerInterceptor runs after Spring's DispatcherServlet has started processing the request (including parsing multipart or JSON bodies), which can consume the request input stream before your interceptor gets a chance to read it. Second, the default ContentCachingRequestWrapper is optimized for form-encoded POSTs, not arbitrary request bodies.

Here's how to fix this and capture request bodies for all request types, methods, and content types in a non-Spring Boot Spring MVC app:

1. Use a Filter Instead of a HandlerInterceptor

Filters execute earlier in the request lifecycle (before the DispatcherServlet), so they can wrap the request before any other component consumes the input stream. Spring's OncePerRequestFilter is perfect here—it ensures the filter runs exactly once per request, avoiding duplicate processing.

Example Filter Implementation

import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class RequestBodyLoggingFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // Wrap the request to cache the body for repeated access
        HttpServletRequest wrappedRequest = new ContentCachingRequestWrapper(request);

        // Pass the wrapped request down the filter chain so other components can use it
        filterChain.doFilter(wrappedRequest, response);

        // Now safely read the cached body for logging/processing
        ContentCachingRequestWrapper cachingWrapper = (ContentCachingRequestWrapper) wrappedRequest;
        byte[] requestBody = cachingWrapper.getContentAsByteArray();

        if (requestBody.length > 0) {
            String bodyContent = new String(requestBody, request.getCharacterEncoding());
            // Add your custom processing here: logging, validation, etc.
            // For example: logger.info("Incoming request body: {}", bodyContent);
        }
    }
}

2. Configure the Filter in web.xml

Since you're not using Spring Boot, you need to register the filter manually in your web.xml to intercept all requests:

<filter>
    <filter-name>requestBodyLoggingFilter</filter-name>
    <filter-class>com.yourpackage.RequestBodyLoggingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>requestBodyLoggingFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <!-- Ensure we intercept all request types (including forwards) -->
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

3. Handle Special Cases (Multipart, GET with Body)

Multipart/Form-Data Requests

The default ContentCachingRequestWrapper won't capture the raw multipart body (since Spring parses it into parts/files before your filter runs). If you need to log multipart data:

  • Check if the request is a MultipartHttpServletRequest after the filter chain runs, then extract form fields and file metadata:
if (wrappedRequest instanceof MultipartHttpServletRequest) {
    MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) wrappedRequest;
    
    // Log form parameters
    Map<String, String[]> formParams = multipartRequest.getParameterMap();
    // Log file details (names, sizes, etc.)
    Map<String, MultipartFile> files = multipartRequest.getFileMap();
}

If you absolutely need the raw multipart body, you'll need a custom HttpServletRequestWrapper that caches the input stream before Spring's MultipartResolver parses it. Just note this may interfere with normal multipart processing, so use it carefully.

GET Requests with Bodies

While uncommon, some clients send bodies with GET requests. The filter above will capture these too, since it wraps the request regardless of HTTP method.

Why This Works Better Than HandlerInterceptor

  • Timing: Filters run before the DispatcherServlet processes the request, so the input stream hasn't been consumed yet.
  • Universal Support: Wrapping the request at the filter level ensures all content types (JSON, plain text, XML, etc.) are cached, not just form-encoded POSTs.
  • Reusability: The wrapped request is available to all downstream components (controllers, interceptors) if they need to re-read the body.

内容的提问来源于stack exchange,提问作者Tabish Mir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 13:37:29