WebSocket连接错误Error during WebSocket handshake Unexpected response code 404
一、问题描述
后台SpringBoot使用@ServerEndpoint创建了一个websocket服务端,本地测试的时候一切正常,部署到线上的时候链接报错
1 | WebSocket connection to 'ws://xxxx' failed: Error during WebSocket handshake: Unexpected response code: 404 |
当项目使用域名+端口号的方式访问的时候ws连接正常,而通过nginx反向代理后ws连接就不正常了。
错误的nginx配置:
1 | server{ |
二、原因分析
Websocket握手格式包:1
2
3
4
5
6
7
8GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
这请求类似http协议,里面多了陌生的内容是:
1 | Upgrade: websocket |
这个就是Websocket的相关的,他会告诉Apache、Nginx等服务器我发起的是websocket请求,不是http!下面的三个参数Sec-WebSocket-Key、Sec-WebSocket-Protocol、Sec-WebSocket-Version作用大概就是验证请求确实是websocket,同时指定协议版本。
三、解决方法
官方地址:http://nginx.org/en/docs/http/websocket.html
nginx配置WebSocket代理
要将客户端和服务器之间的连接从HTTP / 1.1转换为WebSocket,将使用HTTP / 1.1中可用的协议切换机制。
但是,有一个微妙之处:由于“升级”是 逐跳的 标头,因此它不会从客户端传递到代理服务器。使用正向代理,客户端可以使用该CONNECT 方法来规避此问题。但是,这不适用于反向代理,因为客户端不知道任何代理服务器,并且需要对代理服务器进行特殊处理。
从版本1.3.13开始,nginx实施了特殊的操作模式,如果代理服务器返回了代码为101(交换协议)的响应,并且客户端通过以下方式请求协议切换,则允许在客户端与代理服务器之间建立隧道。请求中的“升级”标头。
如上所述,包括“ Upgrade”和“ Connection”的逐跳标头未从客户端传递到代理服务器,因此,为了使代理服务器了解客户端将协议切换到WebSocket的意图,这些标头必须明确传递:
1 | location /chat/ { |
默认情况下,如果代理服务器在60秒内未传输任何数据,则连接将关闭。可以使用proxy_read_timeout指令来增加此超时时间 。或者,可以将代理服务器配置为定期发送WebSocket ping帧以重置超时并检查连接是否仍然有效。
如果不配置超时时间,隔一会就会断开 具体超时时间具体要根据业务来调整。最终的配置如下:
1 | server{ |