【问题标题】:Node, ws, ssl, nginx giving error 426, upgrade needed节点、ws、ssl、nginx 给出错误 426,需要升级
【发布时间】:2018-05-23 20:30:28
【问题描述】:

我正在使用 Node.js 和 NGINX 提供应用程序。我正在使用 LetsEncrypt 保护 NGINX,并使用 pm2 在服务器上运行我的节点应用程序(使用 NGINX 作为反向代理)。

我的网站不会加载任何内容(426 错误 - 需要升级),但我可以使用以下暂存器进行连接:

var port = 443;
var ws = new WebSocket("wss://mywebsite.com:" + port);

ws.onopen = function() {
  console.log("Connected");
}

ws.onmessage = function(comment) {
  console.log(JSON.parse(comment.data));
}

这是 NGINX 设置:

server {

        root /var/www/html;

        # Add index.php to the list if you are using PHP
        index index.html index.htm index.nginx-debian.html;

        server_name mywebsite.com www.mywebsite.com;

        location / {
                proxy_pass http://127.0.0.1:8080/;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
    }

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /path/to/cert; # managed by Certbot
    ssl_certificate_key /path/to/key; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot


}
server {
    if ($host = www.mywebsite.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = mywebsite.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


        listen 80 default_server;
        listen [::]:80 default_server;

        server_name mywebsite.com www.mywebsite.com;
    return 404; # managed by Certbot
}

我的客户端代码与暂存器基本相同。这是相关的服务器端代码:

var WebSocket = require('ws');
var serverPort = 8080;
var wss = new WebSocket.Server({port:serverPort});
console.log("Server running on port " + serverPort + " started at: " + new Date());

wss.on('connection', function(ws) {

        console.log("Connected to websocket: " + ws);
        var introComment = JSON.stringify({
                user: "Welcome!",
                data: {
                        body: "Welcome to the realtime feed!",
                        name: "realtime-intro-connection-message",
                },

        });
        ws.send(introComment);
});

这些是浏览器收到的响应标头:

HTTP/1.1 426 Upgrade Required
Server: nginx/1.10.3 (Ubuntu)
Date: Wed, 23 May 2018 19:20:36 GMT
Content-Type: text/plain
Content-Length: 16
Connection: keep-alive

我读到应该有一个“升级”标题,这是问题的一部分吗?

【问题讨论】:

  • 可能需要改一下:proxy_http_version 1.1;到更高的地方?
  • 这个好像是推荐版本@nginx官方(只有1.0和1.1):nginx.org/en/docs/http/…
  • 你的nodejs服务器发送的http版本是什么?

标签: node.js nginx websocket


【解决方案1】:

为了将客户端和服务器之间的连接从 HTTP/1.1 转换为 WebSocket,使用了 HTTP/1.1 中可用的协议切换机制。

但是有一个微妙之处:由于“升级”是逐跳标头,因此它不会从客户端传递到代理服务器。通过转发代理,客户端可以使用 CONNECT 方法来规避这个问题。但是,这不适用于反向代理,因为客户端不知道任何代理服务器,并且需要在代理服务器上进行特殊处理。

从 1.3.13 版本开始,nginx 实现了特殊的操作模式,如果代理服务器返回带有代码 101(切换协议)的响应,并且客户端请求协议,则允许在客户端和代理服务器之间建立隧道通过请求中的“升级”标头进行切换。

如上所述,包括“升级”和“连接”在内的逐跳标头不会从客户端传递到代理服务器,因此为了让代理服务器了解客户端将协议切换到 WebSocket 的意图,这些标头必须显式传递:

 location /chat/ {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

一个更复杂的示例,其中对代理服务器的请求中的“Connection”标头字段的值取决于客户端请求标头中“Upgrade”字段的存在:

http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

服务器{ ...

    location /chat/ {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

【讨论】:

  • 花了 12 个小时与错误的重定向作斗争,终于找到了这个答案!谢谢!
【解决方案2】:

我从来没有真正找到答案,所以我改变了策略:

我从 ws(npm 的 websockets)移到了 socket.io。这似乎得到了更广泛的支持。有关使用 socket.io 的示例应用程序,请查看 here 这些精彩视频!现在一切正常。

【讨论】:

    猜你喜欢
    • 2021-11-03
    • 1970-01-01
    • 2017-07-08
    • 2019-07-29
    • 1970-01-01
    • 2021-04-21
    • 2021-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多