簡體   English   中英

節點、ws、ssl、nginx 給出錯誤 426,需要升級

[英]Node, ws, ssl, nginx giving error 426, upgrade needed

我正在使用 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

我讀到應該有一個“升級”標題,這是問題的一部分嗎?

為了將客戶端和服務器之間的連接從 HTTP/1.1 轉換為 WebSocket,使用了 HTTP/1.1 中可用的協議切換機制。

然而,有一個微妙之處:由於“升級”是一個逐跳的標頭,它不會從客戶端傳遞到代理服務器。 通過正向代理,客戶端可以使用 CONNECT 方法來規避此問題。 然而,這不適用於反向代理,因為客戶端不知道任何代理服務器,並且需要在代理服務器上進行特殊處理。

從 1.3.13 版本開始,nginx 實現了特殊的操作模式,如果代理服務器返回代碼為 101(切換協議)的響應,並且客戶端通過請求中的“升級”標頭。

如上所述,包括“Upgrade”和“Connection”在內的逐跳標頭不會從客戶端傳遞到代理服務器,因此為了讓代理服務器了解客戶端將協議切換到 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;
    }
}

我從來沒有真正找到答案,所以我改變了策略:

我從 ws(npm 的 websockets)轉移到了 socket.io。 這似乎得到了更廣泛的支持。 對於使用socket.io一個示例應用程序,看看這里的這些偉大的影片! 現在一切正常。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM