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

Spring @RestController响应Content-Type修改:Filter设置不生效问题

如何修复Filter中修改HttpServletResponse的Content-Type不生效问题

我尝试在Filter类中修改HttpServletResponse的Content-Type,但修改未生效。响应的Content-Type仍为application/json,预期应为application/xml。

现有代码

Filter类代码

@Component
@Order(1)
public class TestFilter implements javax.servlet.Filter {
    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
            throws IOException, ServletException {
        if (arg1 instanceof HttpServletResponse) {
            HttpServletResponse httpServletResponse = (HttpServletResponse) arg1;
            httpServletResponse.setContentType("application/xml");
            arg1.setContentType("application/xml");
            
            String contentType = httpServletResponse.getContentType();  
            System.out.println("contentType : "+contentType);
            
            arg2.doFilter(arg0, new HttpServletResponseWrapper(httpServletResponse) {
                @Override
                public void setContentType(final String type) {
                    
                }
            });
            String contentType1 = httpServletResponse.getContentType();
            System.out.println("contentType1 : "+contentType1);
            String contentType2 = httpServletResponse.getContentType();
            System.out.println("contentType2 : "+contentType2);
        }
    }
}

Controller类代码

@RestController
public class TestController {
    
    @PostMapping(path="/test", consumes = MediaType.ALL_VALUE,  
            produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
    public String test() {
        return "<SUCCESS></SUCCESS>";
    }
}

响应日志

contentType : application/xml
contentType1 : application/json
contentType2 : application/json

问题分析

  1. 现有HttpServletResponseWrapper仅重写了setContentType但为空实现,Spring MVC内部可能直接操作原始响应对象的Header设置Content-Type,导致拦截失效。
  2. Controller的produces声明了两种响应类型,Spring MVC会优先根据请求的Accept头选择;若请求未指定Accept,默认会选用数组第一个类型application/json,覆盖Filter中设置的值。

修复方案

方案一:增强Filter的拦截逻辑

修改Filter,同时拦截setContentType和setHeader方法,强制将Content-Type设置为目标值,并且在请求处理完成后再次确认设置:

@Component
@Order(1)
public class TestFilter implements javax.servlet.Filter {
    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
            throws IOException, ServletException {
        if (arg1 instanceof HttpServletResponse) {
            HttpServletResponse httpServletResponse = (HttpServletResponse) arg1;
            final String targetContentType = "application/xml";
            
            // 初始化设置
            httpServletResponse.setContentType(targetContentType);
            System.out.println("contentType : " + httpServletResponse.getContentType());
            
            // 包装响应,拦截所有修改Content-Type的操作
            HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(httpServletResponse) {
                @Override
                public void setContentType(String type) {
                    // 强制使用目标类型
                    super.setContentType(targetContentType);
                }

                @Override
                public void setHeader(String name, String value) {
                    if ("Content-Type".equalsIgnoreCase(name)) {
                        super.setHeader(name, targetContentType);
                    } else {
                        super.setHeader(name, value);
                    }
                }
            };
            
            // 继续执行请求链
            arg2.doFilter(arg0, responseWrapper);
            
            // 最后再确认设置一次,防止遗漏
            httpServletResponse.setContentType(targetContentType);
            System.out.println("contentType after doFilter: " + httpServletResponse.getContentType());
        }
    }
}

方案二:直接修改Controller的produces

如果不需要动态切换响应类型,直接将Controller的produces指定为唯一的application/xml,Spring MVC会直接返回该类型:

@RestController
public class TestController {
    
    @PostMapping(path="/test", consumes = MediaType.ALL_VALUE,  
            produces = MediaType.APPLICATION_XML_VALUE)
    public String test() {
        return "<SUCCESS></SUCCESS>";
    }
}

注意事项

  • 若请求的Accept头明确指定了application/json,方案一的Filter会强制覆盖为application/xml,而方案二会直接返回application/xml,忽略Accept头。
  • Filter的@Order(1)确保它在其他Filter之前执行,避免被后续Filter覆盖设置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 08:05:34