[英]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.