ContentCachingRequestWrapper
是 Spring Framework 中提供的一种包装类,它扩展了 HttpServletRequestWrapper
类,用于缓存请求体的内容。
通常在处理 HTTP 请求时,原生的 HttpServletRequest
对象中的输入流 (getInputStream()
) 只能被读取一次,如果需要多次访问请求体内容(比如在进行过滤、校验或转发请求时),就会遇到问题。
ContentCachingRequestWrapper
解决了这个问题,通过在第一次读取请求体时将数据复制到一个缓冲区中,后续对请求体的读取操作会从这个缓冲区而不是原始输入流中获取数据。这样就允许开发者多次读取请求体而不会抛出异常,并且保持了请求体数据的一致性。
使用 ContentCachingRequestWrapper
时,通常是在应用的前置处理器、拦截器或者过滤器中创建并替换原来的 HttpServletRequest
实例,以便在后面的处理流程中安全地重复访问请求体内容。
使用样例:用在过滤器中
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class RequestBodyCachingFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {// 创建 ContentCachingRequestWrapper 对象来缓存请求体HttpServletRequest wrapper = new ContentCachingRequestWrapper(request);// 继续执行过滤链,并传递包装后的请求对象filterChain.doFilter(wrapper, response);// 在过滤链执行完毕后,可以访问缓存的请求体内容byte[] cachedBody = ((ContentCachingRequestWrapper) wrapper).getContentAsByteArray();// 在此处进行对请求体内容的处理或验证String requestBody = new String(cachedBody, request.getCharacterEncoding());// 示例:打印请求体内容System.out.println("The request body is: " + requestBody);}
}
使用样例:用在过滤器中
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.util.ContentCachingRequestWrapper;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class RequestBodyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 创建 ContentCachingRequestWrapper 对象来缓存请求体ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);// 你可以在这里读取并处理请求体内容,例如进行预处理或验证byte[] cachedBody = wrappedRequest.getContentAsByteArray();String requestBody = new String(cachedBody, request.getCharacterEncoding());// 示例:打印请求体内容System.out.println("The request body is: " + requestBody);// 将包装后的请求对象传递给后续的处理流程request = wrappedRequest;// 如果需要继续执行请求处理,则返回 truereturn true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {// 可以在此处访问已经缓存的请求体数据}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 请求处理完成后,仍可以访问缓存的请求体数据}
}