wss连接的一些坑

一、内容

浏览器控制面板异常信息

Mixed Content: The page at ‘https://{域名}.com/‘ was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint ‘ws://{ip}:{port}/‘. This request has been blocked; this endpoint must be available over WSS.
Uncaught DOMException: Failed to construct ‘WebSocket’: An insecure WebSocket connection may not be initiated from a page loaded over HTTPS.

  • 好家伙,这种情况,毫无疑问我们就需要使用 wss:// 安全协议了,于是立即联系h5客户端,把连接服务端webscoket的形式由ws:// 改为 wss:// 。本以为这样就解决了,没想到一段时间后下一个问题又来了。

扩展:关于 ws 和 wss

WebSocket可以使用 ws 或 wss 来作为统一资源标志符,类似于 HTTP 或 HTTPS。其中 ,wss 表示在 TLS 之上的 WebSocket,相当于 HTTPS。默认情况下,WebSocket的 ws 协议基于Http的 80 端口;当运行在TLS之上时,wss 协议默认是基于Http的 443 端口。说白了,wss 就是 ws 基于 SSL 的安全传输,与 HTTPS 一样样的道理。所以,如果你的网站是 HTTPS 协议的,那你就不能使用 ws:// 了,浏览器会 block 掉连接,和 HTTPS 下不允许 HTTP 请求一样。

  • h5客户端改成wss连接后,测试发现还是无法正常游戏。无奈,再次打开浏览器面板,果然,又看到一个新的问题。

浏览器控制面板异常信息

WebSocket connection to ‘wss://{ip}:{port}/‘ failed: Error in connection establishment: net::ERR_SSL_PROTOCOL_ERROR

  • 之前在Http的情况下,客户端一直是用ip+port的形式来连接服务端,当然了也不会出现什么问题。很明显,在更改成Https后,若还是以这种方式连接服务端,浏览器就会报 SSL 协议错误,这很明显就是证书的问题。如果这时候还用 IP + 端口号 的方式连接 WebSocket ,是根本就没有证书存在的(即使我们在Nginx配置了SSL证书,但这种方式其实是不会走Nginx代理的),所以在生成环境下,更推荐大家用域名的方式来连接。于是,立刻又联系前端,再一次做更改,修改为 wss://{域名}/ 进行连接。我以为这样就真的解决了,没想到还是too young too simple,没一会下个问题又来了,测试反馈的结果还是不可以,第三次打开浏览器控制面板,果然又是一个新的错误信息。

浏览器控制面板异常信息

WebSocket connection to ‘wss://{域名}/‘ failed: Error during WebSocket handshake: Unexpected response code: 400

  • 看到这个错误信息后,确定这是服务端返回的400响应。既然可以请求到服务端,就说明客户端这边是没有问题的,那么问题最可能出在客户端和服务端之间。由于中间层使用了Nginx做转发,所以导致服务端无法知道这是一个合法的WebSocket请求。于是立刻查找了网上资料,在Nginx配置文件加入了以下配置,成功解决了这个问题。
server {
    
    
    location / {
    
    
            proxy_pass http://localhost:{
    
    port};
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
    }
}
  • 接着,连忙拿域名进行再次连接测试,终于看到了101 Switching Protocols的响应Status Code。就这样,也算是终于解决完在 HTTPS 下以 wss://{域名}/ 的方式连接 WebSocket的一系列问题。不过,最后这其中还有一个小问(插)题(曲)。

关于Nginx中的WebSocket配置

自1.3 版本开始,Nginx就支持 WebSocket,并且可以为 WebSocket 应用程序做反向代理和负载均衡。WebSocket 和 HTTP 是两种不同的协议,但是 WebSocket 中的握手和 HTTP 中的握手兼容,它使用 HTTP 中的 Upgrade 协议头将连接从 HTTP 升级到 WebSocket,当客户端发过来一个 Connection: Upgrade请求头时,其实Nginx是不知道的。所以,当 Nginx 代理服务器拦截到一个客户端发来的 Upgrade 请求时,需要我们显式的配置Connection、Upgrade头信息,并使用 101(交换协议)返回响应,在客户端、代理服务器和后端应用服务之间建立隧道来支持 WebSocket。
   当然,还需要注意一点,此时WebSocket 仍然受到 Nginx 缺省为60秒的 proxy_read_timeout 配置影响。这意味着,如果你有一个程序使用了 WebSocket,但又可能超过60秒不发送任何数据的话,那么需要增大超时时间(配置proxy_read_timeout),要么实现一个Ping、Pong的心跳消息以保持客户端和服务端的联系。使用Ping、Pong的解决方法有额外的好处,如:可以发现连接是否被意外关闭等。

  • 关于最后的这个小问题,主要是在对Nginx配置的时候将location=/的请求都进行了proxy_pass(转发)。由于h5客户端的文件打包成静态文件后,存放在服务器的指定目录下(这里假设在/root/html/static/路径下),这也就导致这种配置的情况下Nginx无法正常代理指定目录下的客户端文件。于是再一次修改配置文件,添加location配置,最终完美解决所有问题。
location /static/ {
    
    
    root /root/html;
}

二、相关地址

猜你喜欢

转载自blog.csdn.net/qq_36025814/article/details/108706048