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

SpringBoot中如何通过Filter返回XML格式的响应体?

问题分析与解决方案

在SpringBoot的Filter中,使用response.getWriter()写入JSON格式响应体时能正常被获取,但切换到XML格式时就无法获取响应体,核心原因是XML序列化通常依赖response.getOutputStream()而非字符流Writer,且当前代码未适配XML的序列化逻辑。

修复步骤

1. 适配不同格式的序列化与输出流

根据请求Accept头判断格式类型,分别使用对应的序列化工具和输出方式:

HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.reset();
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
String acceptHeader = request.getHeader(HttpHeaders.ACCEPT);
response.setContentType(acceptHeader);

ErrorVO errorVO = ErrorUtil.createErrorsVO(ErrorTypeEnum.HEADER_NOT_SET, INTUIT_OFFERING_ID);

if (acceptHeader.contains("application/json")) {
    // JSON格式使用字符流Writer
    objectMapper.writeValue(response.getWriter(), errorVO);
} else if (acceptHeader.contains("application/xml")) {
    // XML格式使用字节流OutputStream,需引入Jackson XML模块
    XmlMapper xmlMapper = new XmlMapper();
    xmlMapper.writeValue(response.getOutputStream(), errorVO);
}

2. 添加XML序列化依赖

若使用Jackson处理XML序列化,需在项目中引入对应依赖:

Maven

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

Gradle

implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml'

3. 用响应包装类缓存输出(获取响应体的前提)

原生响应流是一次性的,必须通过HttpServletResponseWrapper包装响应,提前缓存输出内容才能在Filter中获取:

public class CachedResponseWrapper extends HttpServletResponseWrapper {
    private final ByteArrayOutputStream cachedOutputStream;
    private PrintWriter cachedWriter;

    public CachedResponseWrapper(HttpServletResponse response) {
        super(response);
        cachedOutputStream = new ByteArrayOutputStream();
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return new ServletOutputStream() {
            @Override
            public void write(int b) throws IOException {
                cachedOutputStream.write(b);
                getResponse().getOutputStream().write(b);
            }

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

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

    @Override
    public PrintWriter getWriter() throws IOException {
        if (cachedWriter == null) {
            cachedWriter = new PrintWriter(new OutputStreamWriter(cachedOutputStream, getCharacterEncoding()));
        }
        return cachedWriter;
    }

    public byte[] getCachedContent() {
        if (cachedWriter != null) {
            cachedWriter.flush();
        }
        return cachedOutputStream.toByteArray();
    }
}

在Filter中使用包装类:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    CachedResponseWrapper cachedResponse = new CachedResponseWrapper((HttpServletResponse) response);
    chain.doFilter(request, cachedResponse);
    
    // 获取缓存的响应体
    byte[] responseBody = cachedResponse.getCachedContent();
    String responseStr = new String(responseBody, cachedResponse.getCharacterEncoding());
    // 后续处理逻辑...
}

关键注意点

  • getWriter()用于字符型响应(如JSON),getOutputStream()用于字节型响应(如XML),混用会抛出IllegalStateException或导致响应体无法被读取。
  • 必须通过响应包装类缓存输出,否则直接读取原生流会导致前端无法收到正常响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 00:05:25