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

Spring Boot中Filter的doFilter方法无法获取正确响应求助

解决Spring Boot Filter中请求仅返回200的问题

我之前帮不少开发者排查过类似问题,核心原因要么是请求没正常流转到业务处理环节,要么是没法正确获取/返回实际响应内容。下面给你拆解具体解决方案:

先排查最关键的问题:是否调用了FilterChain.doFilter()

你的requestFunction方法里必须确保调用了chain.doFilter(request, response)——这是让请求继续传递到后续控制器、其他过滤器的唯一入口。如果漏掉这一步,请求会直接在过滤器阶段终止,返回的就是Servlet容器默认的200空响应,不会有任何业务处理后的内容。

如果需要获取/修改响应内容,用HttpServletResponseWrapper包装响应

原生的ServletResponse不支持直接读取响应体,如果你想在过滤器里拿到实际的响应内容,得用包装类来捕获响应输出。

第一步:定义响应包装类

public class ContentCachingResponseWrapper extends HttpServletResponseWrapper {
    private final ByteArrayOutputStream cacheStream;
    private ServletOutputStream outputStream;
    private PrintWriter writer;

    public ContentCachingResponseWrapper(HttpServletResponse response) throws IOException {
        super(response);
        this.cacheStream = new ByteArrayOutputStream();
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        if (writer != null) {
            throw new IllegalStateException("getWriter()已经被调用");
        }
        if (outputStream == null) {
            outputStream = new CachingServletOutputStream(getResponse().getOutputStream(), cacheStream);
        }
        return outputStream;
    }

    @Override
    public PrintWriter getWriter() throws IOException {
        if (outputStream != null) {
            throw new IllegalStateException("getOutputStream()已经被调用");
        }
        if (writer == null) {
            writer = new PrintWriter(new OutputStreamWriter(cacheStream, getResponse().getCharacterEncoding())) {
                @Override
                public void flush() {
                    super.flush();
                    try {
                        getResponse().getWriter().flush();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            };
        }
        return writer;
    }

    // 获取缓存的响应内容
    public String getCachedResponseContent() {
        return cacheStream.toString();
    }

    // 将缓存的内容回写到实际响应,确保前端能拿到数据
    public void copyCacheToResponse() throws IOException {
        if (outputStream != null) {
            outputStream.flush();
        }
        if (writer != null) {
            writer.flush();
        }
        byte[] cachedBytes = cacheStream.toByteArray();
        if (cachedBytes.length > 0) {
            ServletOutputStream actualOut = getResponse().getOutputStream();
            actualOut.write(cachedBytes);
            actualOut.flush();
        }
    }

    private static class CachingServletOutputStream extends ServletOutputStream {
        private final ServletOutputStream actualOut;
        private final ByteArrayOutputStream cacheOut;

        public CachingServletOutputStream(ServletOutputStream actualOut, ByteArrayOutputStream cacheOut) {
            this.actualOut = actualOut;
            this.cacheOut = cacheOut;
        }

        @Override
        public boolean isReady() {
            return actualOut.isReady();
        }

        @Override
        public void setWriteListener(WriteListener writeListener) {
            actualOut.setWriteListener(writeListener);
        }

        @Override
        public void write(int b) throws IOException {
            cacheOut.write(b);
            actualOut.write(b);
        }
    }
}

第二步:在过滤器中使用包装类

修改你的doFilter方法,用包装类处理响应,同时确保调用chain.doFilter:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    // 强转为HTTP类型(Spring Boot绝大多数场景都是HTTP请求)
    HttpServletRequest httpReq = (HttpServletRequest) request;
    ContentCachingResponseWrapper wrappedResp = new ContentCachingResponseWrapper((HttpServletResponse) response);

    // 关键:让请求继续流转到后续业务处理环节
    chain.doFilter(httpReq, wrappedResp);

    // 现在可以获取实际的响应状态码和内容了
    int statusCode = wrappedResp.getStatus();
    String responseContent = wrappedResp.getCachedResponseContent();
    System.out.println("当前请求响应状态:" + statusCode);
    System.out.println("响应内容:" + responseContent);

    // 必须调用这个方法,把缓存的响应内容回写到实际响应中,不然前端拿不到数据
    wrappedResp.copyCacheToResponse();
}

几个容易踩坑的点

  • 绝对不能省略chain.doFilter():这是请求进入业务逻辑的必经之路,没调用的话,请求直接在过滤器结束,返回默认200。
  • 包装类必须处理响应回写:如果只缓存响应但不把内容写回实际响应,前端会收到空响应。
  • 类型强转要注意:如果你的应用有非HTTP请求(极少场景),要加类型判断,但Spring Boot常规场景下直接强转没问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:32:22