zoukankan      html  css  js  c++  java
  • 阿里云负载不支持 WebSocket 协议与 WSS 和 Nginx 配置问题

    WebSocket 是 HTML5 下一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的。它与HTTP一样通过已建立的TCP连接来传输数据,但是它和HTTP最大不同是:

    • WebSocket是一种双向通信协议。在建立连接后,WebSocket服务器端和客户端都能主动向对方发送或接收数据,就像Socket一样;
    • WebSocket需要像TCP一样,先建立连接,连接成功后才能相互通信。

    WebSocket 连接本质上是一个 TCP 连接,比较轮询在数据传输的稳定性和数据传输量的大小方面,具有很大的性能优势。

    浏览器请求

    GET / HTTP/1.1
    Upgrade: websocket
    Connection: Upgrade
    Host: example.com
    Origin: null
    Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
    Sec-WebSocket-Version: 13

    客户端发起的WebSocket连接报文类似传统HTTP报文,Upgrade:websocket参数值表明这是WebSocket类型请求,Sec-WebSocket-Key是WebSocket客户端发送的一个 base64编码的密文,要求服务端必须返回一个对应加密的Sec-WebSocket-Accept应答,否则客户端会抛出Error during WebSocket handshake错误,并关闭连接。

    在请求中的Sec-WebSocket-Key是随机的,服务器端会用这些数据来构造出一个SHA-1的信息摘要。把Sec-WebSocket-Key加上一个魔幻字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11。使用 SHA-1 加密,之后进行 BASE-64编码,将结果作为 Sec-WebSocket-Accept 头的值,返回给客户端;WebSocket 先是通过 HTTP 建立连接, 然后通过 101 状态码, 表示切换协议,在配置里是 Upgrade。

    服务器回应

    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
    Sec-WebSocket-Origin: null
    Sec-WebSocket-Location: ws://example.com/

    Sec-WebSocket-Accept 的值是服务端采用与客户端一致的密钥计算出来后返回客户端的,HTTP/1.1 101 Switching Protocols表示服务端接受WebSocket协议的客户端连接,经过这样的请求-响应处理后,两端的WebSocket连接握手成功, 后续就可以进行TCP通讯了。用户可以查阅WebSocket协议栈了解WebSocket客户端和服务端更详细的交互数据格式。

    浏览器兼容性

    最新的主流浏览器对WebSocket支持良好:

    • Chrome 4+
    • Firefox 4+
    • Internet Explorer 10+
    • Opera 10+
    • Safari 5+

    我们在阿里云启用全站 HTTPS 后,我们发现阿里云 webscoket 通信报错 400 Bad Request 错误,开始以为是启用HTTPS的问题,后面发现阿里云的负载均衡(LB)根本就不支持 ws 协议(https://help.aliyun.com/document_detail/63421.html?spm=5176.doc63420.6.714.hC3lA2),Google 了一番,决定使用 nginx 代理。

    备注:阿里 ws 与 http2 支持情况 https://yq.aliyun.com/articles/277584?spm=5176.10695662.1996646101.searchclickresult.2a8d761c2PJag1

    Request URL:wss://singalr.xxx.cn/signalr/connect?transport=webSockets&clientProtocol=1.5&connectionToken=xmpmOB19Q6d7X32GFEP7lTFm7DPSJIcRALZOxbASrpogN5MPTTBafipQsNBs0x5J7wvUm5QI8e1iViqETc9Q8%2FGHCLZo5GhJsXYRWmOzsICh5LDyQDGnAsRSC3GvBMsQ&connectionData=%5B%7B%22name%22%3A%22signalrpushhub%22%7D%5D&tid=9
    Request Method:GET
    Status Code:400 Bad Request
    
    Response Headers
    Access-Control-Allow-Credentials:true
    Access-Control-Allow-Origin:https://xxx.cn
    Cache-Control:no-cache
    Connection:keep-alive
    Content-Type:text/html
    Date:Wed, 17 May 2017 02:09:56 GMT
    Expires:-1
    Pragma:no-cache
    Transfer-Encoding:chunked
    X-AspNet-Version:4.0.30319
    X-Content-Type-Options:nosniff
    X-Powered-By:ASP.NET
    
    Response Headers
    Accept-Encoding:gzip, deflate, sdch, br
    Accept-Language:zh-CN,zh;q=0.8
    Cache-Control:no-cache
    Connection:Upgrade
    Cookie:_pms_session=5d0gqrezzfgvivj2b4oaecy3; acw_tc=AQAAAMvoFF/VeQoAJkNKfD0idg5CQvGL
    Host:singalr.xxx.cn
    Origin:https://p2.xxx.cn
    Pragma:no-cache
    Sec-WebSocket-Extensions:permessage-deflate; client_max_window_bits
    Sec-WebSocket-Key:V2NZvyJw/CJtAdn68xDZWA==
    Sec-WebSocket-Version:13
    Upgrade:websocket
    User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36
    
    Query String Parameters
    transport:webSockets
    clientProtocol:1.5
    connectionToken:xmpmOB19Q6d7X32GFEP7lTFm7DPSJIcRALZOxbASrpogN5MPTTBafipQsNBs0x5J7wvUm5QI8e1iViqETc9Q8/GHCLZo5GhJsXYRWmOzsICh5LDyQDGnAsRSC3GvBMsQ
    connectionData:[{"name":"signalrpushhub"}]
    tid:9

    WebSocket 的 Nginx 配置

     开始以为是 HTTPS 443 监听的问题,后面修发现HTTP下ws协议也不可以,咨询了一番,最后发现是阿里云负载均衡不支持 ws 协议的问题。单独把 signalr 的服务端使用 nginx 代理负载 ,其他服务器还是使用阿里云的负载

    upstream singalr { 
       server 192.168.1.5;
       server 192.168.1.4; 
    }
    
    server {
        listen       443 ssl;
        server_name  singalr.com; 
        #charset koi8-r; 
        #access_log logs/host.access.log main;
    
        ssl on;
        ssl_certificate /etc/ssl/private/xxxx.pem;
        ssl_certificate_key /etc/ssl/private/xxx.key;
        
        location / { 
            proxy_pass http://singalr;
            proxy_redirect    off;
    
            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_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    }

    REFER:
    http://nginx.org/en/docs/http/websocket.html
    https://socket.io/
    https://github.com/SignalR/SignalR
    https://github.com/aspnet/SignalR
    http://blog.mixu.net/2011/08/13/nginx-websockets-ssl-and-socket-io-deployment/
    https://docs.microsoft.com/en-us/aspnet/signalr/overview/performance/scaleout-with-redis
    http://www.ruanyifeng.com/blog/2017/05/websocket.html
    WebSocket 实现原理
    http://zeeyang.com/2017/07/02/websocket/
    https://www.qcloud.com/document/product/214/4150
    https://www.zhihu.com/question/20215561

  • 相关阅读:
    300+值得收藏的设计师免费资源站
    Apache 隐藏入口文件 index.php
    Nginx 虚拟主机下支持Pathinfo并隐藏入口文件的完整配置
    Java多线程
    Java注解
    Java异常机制
    面向对象
    数组
    Java方法(函数)
    Java流程控制(Scanner)
  • 原文地址:https://www.cnblogs.com/Irving/p/6872473.html
Copyright © 2011-2022 走看看