WebSocket 结合 Nginx 实现 WSS 协议访问

了解 WebSocket

可以参考维基百科:https://zh.wikipedia.org/wiki/WebSocket
或知乎网友回答:https://www.zhihu.com/question/20215561/answer/40316953

Nginx 反向代理 WebSocket (需要Nginx 1.3+)

在开发中遇到了,部分生产环境,NginxWebSocket 不在同一台服务的情况,可以通过 Nginx 做反向代理。

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 使用 wswss 的统一资源标志符,类似于 HTTPHTTPS,其中 wss 表示在 TLS 之上的 WebSocket ,相当于 HTTPS 了。
默认情况下,WebSocketws 协议使用 80 端口;运行在TLS之上时,wss 协议默认使用 443 端口。其实说白了,wss 就是 ws 基于 SSL 的安全传输,与 HTTPS 一样的道理。

如果你的网站是 HTTPS 协议的,那你就不能使用 ws:// 了,浏览器会 block 掉连接,和 HTTPS 下不允许 HTTP 请求一样.

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:// ,改好之后尝试会报错:

WebSocket connection to 'wss://IP地址:端口号/websocket' failed: Error in connection establishment: net::ERR_SSL_PROTOCOL_ERROR  

明显的 SSL 协议错误,说明是证书的问题。

Nginx 配置支持 WSS

在配置 HTTPS server {} 中(必须是这里,不然ssl无效)加入如下配置:

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 应用程序做反向代理和负载均衡。
WebSocketHTTP 协议不同,但是 WebSocket 中的握手和 HTTP 中的握手兼容,它使用 HTTP 中的 Upgrade 协议头将连接从 HTTP 升级到 WebSocket,当客户端发过来一个 Connection: Upgrade 请求头时,Nginx 是不知道的,所以,当 Nginx 代理服务器拦截到一个客户端发来的 Upgrade 请求时,需要显式来设置 ConnectionUpgrade 头信息,并使用 101(交换协议)返回响应,在客户端和代理服务器、后端服务器之间建立隧道来支持 WebSocket

当然,还需要注意一下,WebSockets 仍然受到 Nginx 缺省为 60 秒的 proxy_read_timeout 的影响。这意味着,如果你有一个程序使用了 WebSockets,但又可能超过 60 秒不发送任何数据的话,那你要么需要增加超时时间,要么实现一个 ping 的消息以保持联系。使用 ping 的解决方法有额外的好处,可以发现连接是否被意外关闭。
更具体文档详见 Nginx 官方文档:http://nginx.org/en/docs/http/websocket.html

本文转载自CSDN博文,在开发中也遇到了类似问题,有少许改动,记录下。