当远程但不是本地时,Socket.io 退回到 nginx 代理后面的轮询(websocket 给出 400)
Posted
技术标签:
【中文标题】当远程但不是本地时,Socket.io 退回到 nginx 代理后面的轮询(websocket 给出 400)【英文标题】:Socket.io falling back to polling (websocket gives 400) behind nginx proxy when remote but not local 【发布时间】:2015-02-06 11:37:54 【问题描述】:我使用 nginx 1.4.6 作为 Django 应用程序和使用 socket.io 1.2.1 和 socketio-jwt 2.3.5 的相关 NodeJS 应用程序的代理
在本地,我使用 Vagrant 实例(ubuntu 14.04.1)进行编码,而远程我使用的是专用的 AWS EC2 实例——两者都使用相同的 Vagrantfile 和设置 shell 脚本进行配置,因此它们非常接近相同。
在本地运行时,我的客户端连接到 nginx 服务器,该服务器升级连接并将其传递给 Node 下的 socket.io 服务器实现。一切都很好。
远程,我用transport=polling
记录第一个连接,它还指示客户端升级到websocket 传输,然后用transport=websockets
记录第二个请求,然后再次用transport=polling
记录第三个请求。
虽然应用程序仍然可以工作,但出于多种原因轮询
第二个请求以400 Bad Request
回答。使用DEBUG=* node index.js
运行我的 Node 应用程序会得到以下输出:
engine intercepting request for path "/socket.io/" +24s
engine handling "GET" http request "/socket.io/?token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Im1hcmNlbCIsIm9yaWdfaWF0IjoxNDE4MDU5ODg1LCJ1c2VyX2lkIjozLCJlbWFpbCI6IiIsImV4cCI6MTQxODE0NjI4NX0.2PE0TNRol9G4hby4OzQ-af2e0yjfgFAb-gQJF5tKWRwxWnFLv1NGp3Yo87UaqNaQceMW6KqzMIx2gLcRFnk09A&EIO=3&transport=polling&t=1418062322853-0" +0ms
engine handshaking client "6YDFOjBfvZ9UyutVAAAB" +1ms
engine:socket sending packet "open" ("sid":"6YDFOjBfvZ9UyutVAAAB","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":60000) +0ms
engine:polling setting request +0ms
engine:socket flushing buffer to transport +0ms
engine:polling writing " �0"sid":"6YDFOjBfvZ9UyutVAAAB","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":60000" +1ms
engine:socket executing batch send callback +1ms
socket.io:server incoming connection with id 6YDFOjBfvZ9UyutVAAAB +1.7m
socket.io:client connecting to namespace / +1.7m
socket.io:namespace adding socket to nsp / +1.7m
socket.io:socket socket connected - writing packet +1.7m
socket.io:socket joining room 6YDFOjBfvZ9UyutVAAAB +0ms
socket.io:client writing packet "type":0,"nsp":"/" +79ms
socket.io-parser encoding packet "type":0,"nsp":"/" +1.7m
socket.io-parser encoded "type":0,"nsp":"/" as 0 +0ms
engine:socket sending packet "message" (0) +79ms
socket id: "6YDFOjBfvZ9UyutVAAAB" connected to user: "marcel"
socket.io:socket joined room 6YDFOjBfvZ9UyutVAAAB +1ms
engine intercepting request for path "/socket.io/" +121ms
engine handling "GET" http request "/socket.io/?token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Im1hcmNlbCIsIm9yaWdfaWF0IjoxNDE4MDU5ODg1LCJ1c2VyX2lkIjozLCJlbWFpbCI6IiIsImV4cCI6MTQxODE0NjI4NX0.2PE0TNRol9G4hby4OzQ-af2e0yjfgFAb-gQJF5tKWRwxWnFLv1NGp3Yo87UaqNaQceMW6KqzMIx2gLcRFnk09A&EIO=3&transport=polling&t=1418062323048-1&sid=6YDFOjBfvZ9UyutVAAAB" +0ms
engine setting new request for existing client +1ms
engine:polling setting request +0ms
engine:socket flushing buffer to transport +1ms
engine:polling writing "�40" +38ms
engine:socket executing batch send callback +1ms
engine intercepting request for path "/socket.io/" +0ms
engine handling "GET" http request "/socket.io/?token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Im1hcmNlbCIsIm9yaWdfaWF0IjoxNDE4MDU5ODg1LCJ1c2VyX2lkIjozLCJlbWFpbCI6IiIsImV4cCI6MTQxODE0NjI4NX0.2PE0TNRol9G4hby4OzQ-af2e0yjfgFAb-gQJF5tKWRwxWnFLv1NGp3Yo87UaqNaQceMW6KqzMIx2gLcRFnk09A&EIO=3&transport=websocket&sid=6YDFOjBfvZ9UyutVAAAB" +1ms
engine bad request: unexpected transport without upgrade +0ms
engine intercepting request for path "/socket.io/" +120ms
engine handling "GET" http request "/socket.io/?token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Im1hcmNlbCIsIm9yaWdfaWF0IjoxNDE4MDU5ODg1LCJ1c2VyX2lkIjozLCJlbWFpbCI6IiIsImV4cCI6MTQxODE0NjI4NX0.2PE0TNRol9G4hby4OzQ-af2e0yjfgFAb-gQJF5tKWRwxWnFLv1NGp3Yo87UaqNaQceMW6KqzMIx2gLcRFnk09A&EIO=3&transport=polling&t=1418062323180-2&sid=6YDFOjBfvZ9UyutVAAAB" +1ms
engine setting new request for existing client +0ms
engine:polling setting request +0ms
这个问题似乎与engine bad request: unexpected transport without upgrade +0ms
行有关,但我不明白。 nginx 配置肯定提到了升级,它适用于我的流浪机器。
nginx config的相关部分如下:
server
...
location /
...
location /socket.io/
proxy_pass http://127.0.0.1:4000/socket.io/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_redirect off;
我能想到的本地和远程设置之间的唯一区别是,在本地,客户端在两个不同的端口上连接到 localhost(我在 nginx 后面代理 Node 应用程序,但 Web 应用程序通过 Gulp 运行),远程时,Node 应用程序位于端口 80 后面的不同域中。
任何线索都非常感谢:)
【问题讨论】:
如果有人有兴趣,我放弃了 nginx 代理,直接打开另一个端口到 NodeJS,一切正常。不过,我仍然很想知道是否有人对此问题有任何想法:/ 我遇到了同样的问题,正在寻找答案。如果你同时发现了一些东西,这里有更多细节......***.com/questions/19031201/… 【参考方案1】:我也遇到过同样的问题。在查看了一些 tcp 捕获后,看起来 nginx 甚至没有收到传入的 Upgrade 标头,因此它没有将其传递给 node.js。 (我确实怀疑 cloudflare 会这样做,但我不确定)。
我解决这个问题的方法很老套,但效果很好。基本上我修改了 nginx 配置以查找Sec-Websocket-Key
标头,当它找到时,它将升级标头设置为websocket
,并将连接标头设置为upgrade
。这行得通。
示例配置:
map $http_sec_websocket_key $upgr
"" ""; # If the Sec-Websocket-Key header is empty, send no upgrade header
default "websocket"; # If the header is present, set Upgrade to "websocket"
map $http_sec_websocket_key $conn
"" $http_connection; # If no Sec-Websocket-Key header exists, set $conn to the incoming Connection header
default "upgrade"; # Otherwise, set $conn to upgrade
您必须在 server
块之前定义这 2 个地图块。
现在在您的 socket.io 位置添加以下 2 行:
proxy_set_header Upgrade $upgr;
proxy_set_header Connection $conn;
这会将 Upgrade 和 Connection 标头设置为映射值。
我希望这也能解决您的问题。
【讨论】:
嗯。它工作得很好,但是将这样的解决方法放入生产机器的配置中感觉有点不对。我将保留这个问题,希望我们能得到一个“真正的”答案——尽管感谢你走到这一步!我还没有准备好使用我的设置,但我很难相信 AWS 基础设施会剥离标头...? 因为它有效。导致我这个问题的原因实际上是没有 cloudflare 的。 Cloudflare 免费帐户不允许使用 websockets。以上是关于当远程但不是本地时,Socket.io 退回到 nginx 代理后面的轮询(websocket 给出 400)的主要内容,如果未能解决你的问题,请参考以下文章