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
相关产品推荐
相关产品推荐

