如何阻止Tomcat发送Connection: close响应头?
解决Tomcat Websocket HTTPS下Connection头重复导致Safari断开问题
我之前也碰到过类似的坑!你的问题是Tomcat在HTTPS连接处理Websocket握手时,响应头里同时返回了Connection: upgrade和Connection: close,这会让Safari判定连接异常直接断开,而HTTP连接正常是因为HTTP场景下Tomcat的处理逻辑没问题。下面给你几个靠谱的解决方法:
方法一:改用NIO协议的Connector(最推荐)
你当前HTTPS Connector用的是旧的阻塞IO协议org.apache.coyote.http11.Http11Protocol,这个协议在处理Websocket的HTTPS握手时容易出现头重复的问题。换成非阻塞的NIO协议就能解决:
修改你的HTTPS Connector配置如下:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" SSLEnabled="true" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="你的密钥库路径" keystorePass="你的密钥库密码" connectionTimeout="20000" disableUploadTimeout="true" />
Http11NioProtocol是Tomcat推荐的现代非阻塞IO协议,对Websocket的支持更完善,不会错误添加Connection: close头- 补充
connectionTimeout和disableUploadTimeout是为了和HTTP Connector的配置保持一致,避免额外的兼容性问题
方法二:添加自定义过滤器移除多余头(备选)
如果改协议后还是有问题,可以通过过滤器手动修正响应头:
首先创建一个过滤器类:
import javax.servlet.*; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class ConnectionHeaderFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse httpResponse = (HttpServletResponse) response; chain.doFilter(request, response); // 检查并修正Connection头 String connectionHeader = httpResponse.getHeader("Connection"); if (connectionHeader != null && connectionHeader.contains("close") && connectionHeader.contains("upgrade")) { httpResponse.setHeader("Connection", "upgrade"); } } @Override public void destroy() {} }
然后在web.xml里配置这个过滤器,让它作用在你的Websocket端点上:
<filter> <filter-name>ConnectionHeaderFilter</filter-name> <filter-class>com.yourpackage.ConnectionHeaderFilter</filter-class> </filter> <filter-mapping> <filter-name>ConnectionHeaderFilter</filter-name> <url-pattern>/你的Websocket端点路径/*</url-pattern> </filter-mapping>
这个过滤器会在响应发送前检查Connection头,如果同时包含upgrade和close,就把它替换成只保留upgrade,从根源上解决Safari的断开问题。
方法三:升级Tomcat版本(兜底)
如果你的Tomcat版本比较旧(比如Tomcat 7或更早),这个问题可能是Tomcat的已知bug,升级到Tomcat 8.5或Tomcat 9以上的稳定版本,官方已经修复了这类Websocket握手的头处理问题。
内容的提问来源于stack exchange,提问作者Jan Knoblauch
相关产品推荐
相关产品推荐

