## 了解 `WebSocket`
可以参考维基百科:https://zh.wikipedia.org/wiki/WebSocket
或知乎网友回答:https://www.zhihu.com/question/20215561/answer/40316953
## Nginx 反向代理 WebSocket (需要Nginx 1.3+)
在开发中遇到了,部分生产环境,`Nginx` 和 `WebSocket` 不在同一台服务的情况,可以通过 `Nginx` 做反向代理。
```bash
http {
// ...省略
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 2425; #监听2425
server_name localhost;
location / {
proxy_pass http://localhost:xxx; #代理xxx
#proxy_connect_timeout 60;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#proxy_set_header X-NginX-Proxy true;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 这是配置webpysessoin丢失的问题
fastcgi_param SCRIPT_NAME "";
}
}
// ...省略
}
```
## `ws` VS `wss`
`WebSocket` 使用 `ws` 或 `wss` 的统一资源标志符,类似于 `HTTP` 或 `HTTPS`,其中 `wss` 表示在 TLS 之上的 `WebSocket` ,相当于 `HTTPS` 了。
默认情况下,`WebSocket` 的 `ws` 协议使用 `80` 端口;运行在TLS之上时,`wss` 协议默认使用 `443` 端口。其实说白了,`wss` 就是 `ws` 基于 SSL 的安全传输,与 `HTTPS` 一样的道理。
如果你的网站是 `HTTPS` 协议的,那你就不能使用 `ws://` 了,浏览器会 block 掉连接,和 `HTTPS` 下不允许 `HTTP` 请求一样.
```bash
Mixed Content: The page at 'https://domain.com/' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://x.x.x.x:xxxx/'. This request has been blocked; this endpoint must be available over WSS.
```
这种情况,毫无疑问我们就需要使用 `wss://` 安全协议了,首先把 `ws://` 改为 `wss://` ,改好之后尝试会报错:
```bash
WebSocket connection to 'wss://IP地址:端口号/websocket' failed: Error in connection establishment: net::ERR_SSL_PROTOCOL_ERROR
```
明显的 `SSL` 协议错误,说明是证书的问题。
## Nginx 配置支持 WSS
在配置 `HTTPS` server {} 中(必须是这里,不然ssl无效)加入如下配置:
```bash
location /websocket {
proxy_pass http://127.0.0.1:xx;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
```
再次连接试一下,不出意外会看 `101` 状态码,至此大功告成。
## 后记
`Nginx` 自从 `1.3` 版本就开始支持 `WebSocket` 了,并且可以为 `WebSocket` 应用程序做反向代理和负载均衡。
`WebSocket` 和 `HTTP` 协议不同,但是 `WebSocket` 中的握手和 `HTTP` 中的握手兼容,它使用 `HTTP` 中的 `Upgrade` 协议头将连接从 `HTTP` 升级到 `WebSocket`,当客户端发过来一个 `Connection: Upgrade` 请求头时,`Nginx` 是不知道的,所以,当 `Nginx` 代理服务器拦截到一个客户端发来的 `Upgrade` 请求时,需要显式来设置 `Connection` 、`Upgrade` 头信息,并使用 `101`(交换协议)返回响应,在客户端和代理服务器、后端服务器之间建立隧道来支持 `WebSocket`。
当然,还需要注意一下,`WebSockets` 仍然受到 `Nginx` 缺省为 60 秒的 `proxy_read_timeout` 的影响。这意味着,如果你有一个程序使用了 `WebSockets`,但又可能超过 60 秒不发送任何数据的话,那你要么需要增加超时时间,要么实现一个 ping 的消息以保持联系。使用 ping 的解决方法有额外的好处,可以发现连接是否被意外关闭。
更具体文档详见 Nginx 官方文档:http://nginx.org/en/docs/http/websocket.html
本文转载自[CSDN博文](http://www.cnblogs.com/mafly/p/websocket.html),在开发中也遇到了类似问题,有少许改动,记录下。
WebSocket 结合 Nginx 实现 WSS 协议访问