Tomcat 8.5中如何保留Content-Type响应头分号后的空格?
我之前碰到过一模一样的遗留系统兼容性问题,Tomcat 8.5确实会对Content-Type头做规范化处理,自动把分号和charset之间的空格删掉——这是因为它内部的org.apache.catalina.connector.Response类在处理内容类型时,会调用org.apache.tomcat.util.http.ContentType的格式化逻辑,强制把格式统一成不带空格的text/xml;charset=utf-8,完全不管你手动设置的格式。
下面给你几个经过验证的可行解决方案:
方案一:直接设置响应头,绕过setContentType
别用response.setContentType()方法,直接通过setHeader()手动写入完整的Content-Type字符串,这样能绕过Tomcat的规范化处理:
// 一定要在获取输出流/Writer之前调用这个方法 response.setHeader("Content-Type", "text/xml; charset=utf-8");
注意必须在调用response.getWriter()或response.getOutputStream()之前设置这个头,一旦输出流被获取,响应头就可能已经被提交,无法修改了。
方案二:自定义响应包装器,强制保留格式
如果你的代码里大量使用了setContentType,不想逐个修改的话,可以写一个自定义的HttpServletResponseWrapper,覆盖相关方法来强制保留空格:
public class SpacePreservingResponseWrapper extends HttpServletResponseWrapper { public SpacePreservingResponseWrapper(HttpServletResponse response) { super(response); } @Override public void setContentType(String type) { // 匹配目标格式时,直接设置原始头 if ("text/xml; charset=utf-8".equals(type)) { super.setHeader("Content-Type", "text/xml; charset=utf-8"); } else { super.setContentType(type); } } @Override public void setHeader(String name, String value) { // 拦截Content-Type头,强制替换成带空格的格式 if ("Content-Type".equalsIgnoreCase(name) && value.contains("text/xml") && value.contains("charset=utf-8")) { super.setHeader(name, "text/xml; charset=utf-8"); } else { super.setHeader(name, value); } } }
然后在过滤器中使用这个包装器,确保它在所有其他过滤器之前执行:
public class ContentTypeFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse wrappedResponse = new SpacePreservingResponseWrapper((HttpServletResponse) response); chain.doFilter(request, wrappedResponse); } @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void destroy() {} }
最后记得在web.xml里配置这个过滤器,优先级设高一点:
<filter> <filter-name>ContentTypeFilter</filter-name> <filter-class>com.yourpackage.ContentTypeFilter</filter-class> </filter> <filter-mapping> <filter-name>ContentTypeFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
方案三:修改Tomcat全局配置(不推荐)
你也可以尝试修改Tomcatconf/web.xml里的mime映射,但这种方式会影响所有部署在该Tomcat上的应用,灵活性很差,而且测试下来Tomcat可能还是会对这个配置做规范化处理,所以优先级最低:
<mime-mapping> <extension>xml</extension> <mime-type>text/xml; charset=utf-8</mime-type> </mime-mapping>
总结一下,方案一和方案二是最稳妥的,前者简单直接,后者适合需要批量兼容的场景,都能完美满足遗留客户端的格式要求。
内容的提问来源于stack exchange,提问作者troig

