Websocket 连接尝试失败,返回“连接:升级,关闭”。

Posted

技术标签:

【中文标题】Websocket 连接尝试失败,返回“连接:升级,关闭”。【英文标题】:Websocket connection attempt fails, returns "Connection: Upgrade, close." 【发布时间】:2018-05-10 20:37:12 【问题描述】:

我正在使用 Tomcat 构建 Java websocket 服务器。在我的开发版本中,它运行良好。但是,当我将其部署到生产环境时,服务器会自动将“关闭”附加到连接响应标头,立即关闭套接字(它似乎从一开始就从未连接到服务器)。

以下是生产环境的一些上下文:

Tomcat 7、RHEL 上的 Java 8 通信使用 SSL 加密,websocket 使用 wss 服务器位于机构防火墙后面(但我希望加密应该不会出现此问题)

我的本​​地开发环境不是一个精确的克隆(因为它用于多个项目)。它运行的是 Tomcat 8,但我相信 Tomcat 7 应该具有类似的 websocket 支持。

以下是 websocket 发送到生产服务器时的请求/响应(由 Chrome 开发工具捕获):

一般:

Request URL: wss://example.com/WSServer
Request Method: GET
Status Code: 101 Switching Protocols

回复:

HTTP/1.1 101 Switching Protocols
Date: Thu, 10 May 2018 17:04:39 GMT
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Upgrade: websocket
Connection: upgrade, close
Sec-WebSocket-Accept: JFNyciPc/Cza8PFaXWVct6f21qw=
Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15
Content-Length: 0
Content-Type: text/plain; charset=UTF-8

请求:

Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cache-Control: no-cache
Connection: Upgrade
Cookie: *redacted*
Host: example.com
Origin: https://example.com
Pragma: no-cache
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: OvMcwMxIYqBLrx9ijlFK/w==
Sec-WebSocket-Version: 13
Upgrade: websocket
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/66.0.3359.139 Safari/537.36`

据我所知,其中最具启发性的部分是 Connection: upgrade, close,它解释了下面的客户端行为。

这是客户端 javascript 的 sn-p:

var socket = new WebSocket((window.location.protocol==="http:"?"ws:":"wss:") + "//" + window.location.host + "/WSServer");

socket.onopen = function wsOpen() 
    socket.send("Hello!"));


socket.onclose = function wsClose(reason) 
    log(JSON.stringify(reason)); //debug

socket.onopen 首先被调用。正常执行,这不会产生任何控制台消息,但是如果我用断点延迟它的执行,我会收到一条错误消息:“Websocket 已经处于 CLOSED 或 CLOSING 状态。”

socket.onclose 之后立即被调用。原因码是1006,不解释。

我还在 ServerEndpointConfig.Configurator.modifyHandshake 方法中添加了一些调试日志记录,但它从未达到那个点,也没有达到 @OnOpen 注释的方法。

知道是什么导致连接失败吗?同样,服务器和客户端代码在 dev 中工作,所以我相信这不是代码问题。是否是 Tomcat 配置问题(据我所知,它的设置方式没有什么异常)。我有什么明显的遗漏吗?

提前感谢您的帮助!

【问题讨论】:

生产环境中好像有代理,没有配置成允许webSocket连接。 @jfriend00 谢谢!但是我认为代理或防火墙无法识别加密的 websocket 传输或发起的 HTTPS 请求(它看起来就像任何其他 TCP 流量)。不是这样吗?另外,如果重要的话,根据websocketstest.com,我可以在网络内的端口 443 上建立 websocket 连接。 在托管环境中,代理通常是 HTTPS 的实际端点。 WebSocket 的实际使用要求任何处理 HTTP(和 WS)协议的反向代理了解如何处理该协议。除了根据 TCP/IP 或 UDP/IP 标头中的内容过滤数据包外,防火墙通常不做任何事情。如果您实际上有一个反向代理,它可能正在终止 HTTPS。如果它正在终止 HTTPS,那么它还必须了解如何处理 WebSocket。 谢谢你们。这件事我得跟上级商量。非常感谢您的帮助。 【参考方案1】:

HTTP/1.1 默认启用保持连接。 一个请求,例如:

GET / HTTP/1.1
Host: example.com
Connection: close

告诉服务器在连接上禁用 keep-alive(与 HTTP/1.1 默认相反)

Upgrade 是一个逐跳标头,就像Connection 一样,而Upgrade 只有在Connection 中列出时才有效,例如Connection: Upgrade

当客户端发出包含Upgrade 的 HTTP/1.1 请求时,接收请求的服务器不需要升级,而是可以简单地响应 HTTP/1.1 响应。

Connection: upgrade, close 请求服务器升级到Upgrade 标头中的协议(之一),或者以 HTTP/1.1 响应并关闭连接。如果服务器升级协议,则服务器使用新协议,而Connection 中的close 令牌将被忽略,因为服务器现在在Upgrade 响应标头中紧跟HTTP/1.1 101 Switching Protocols 之后使用升级后的协议回应。

【讨论】:

以上是关于Websocket 连接尝试失败,返回“连接:升级,关闭”。的主要内容,如果未能解决你的问题,请参考以下文章

go语言聊天室实现(六)创建HTTP连接,并升级为长连接

websocket 升级是不是仍然允许 http ajax 请求?

React-Native 上的连接升级

WebSocket 连接失败。 WebSocket握手期间出错-socketjs

Ubuntu 13.10 中的 websocket 连接失败

websocket连接失败?