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

Spring Boot 2.7.4中如何在Post HandlerInterceptor获取HttpServletResponse响应体

问题分析与解决方案

你当前实现获取响应体为空的原因有两点:

  1. 执行时机不对:HandlerInterceptor.postHandle()在Controller方法执行完成后、响应体被Spring消息转换器写入到HttpServletResponse之前执行,此时响应体还未生成,自然无法获取。
  2. 未正确包装响应对象:直接在postHandle()中创建ContentCachingResponseWrapper,但并未将其替换到请求处理流程中,后续的响应写入操作不会被缓存。

方案一:Filter + Interceptor 组合实现

通过Servlet Filter提前包装响应对象,确保所有响应写入都被缓存,再在Interceptor的afterCompletion()阶段(响应已写入完成)获取内容。

步骤1:创建响应缓存Filter

@Component
public class ResponseCachingFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        ContentCachingResponseWrapper cachedResponse = new ContentCachingResponseWrapper((HttpServletResponse) response);
        try {
            // 继续执行后续请求流程,所有响应写入都会被缓存到cachedResponse
            chain.doFilter(request, cachedResponse);
        } finally {
            // 将缓存的响应内容写入原始响应,确保客户端能正常收到响应
            cachedResponse.copyBodyToResponse();
        }
    }
}

步骤2:修改Interceptor代码

@Component
@Order(1)
public class CustomPostHandlerInterceptor implements HandlerInterceptor {

    @Override
    public final boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    @Override
    public final void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 此阶段响应体未生成,无法获取有效内容
    }

    @Override
    public final void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        if (response instanceof ContentCachingResponseWrapper) {
            ContentCachingResponseWrapper cachedResp = (ContentCachingResponseWrapper) response;
            byte[] responseBody = cachedResp.getContentAsByteArray();
            String res = new String(responseBody, StandardCharsets.UTF_8);
            // 在这里处理响应体,例如打印日志、存储等
            System.out.println("获取到的响应体:" + res);
        }
    }
}

方案二:使用ResponseBodyAdvice(更适合RestController场景)

如果你的需求仅针对@RestController或@ResponseBody注解的接口响应,使用ResponseBodyAdvice会更简洁,无需包装响应流:

@Component
@Order(1)
public class CustomResponseBodyAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 匹配所有返回@ResponseBody的方法,可根据需要调整过滤规则
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // 直接获取响应体内容
        if (body instanceof String) {
            System.out.println("响应体内容:" + body);
        }
        // 返回原响应体,不修改响应内容
        return body;
    }
}

关键说明

  • ContentCachingResponseWrapper必须调用copyBodyToResponse(),否则缓存的内容不会传递给客户端,导致客户端收不到响应。
  • afterCompletion()是Interceptor中唯一能确保响应体已完全写入的阶段。
  • ResponseBodyAdvice直接作用于消息转换器处理后的响应体,无需处理流缓存,更适合REST接口场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 18:20:31