龙卷风nginx websockets握手400错误
Tornado nginx websockets handshake 400 error
问题出在 websocket 连接上,由 nginx 从 tornado/tornado-sockjs 代理到浏览器中的 sockjs 客户端。没有 nginx(在本地主机上)一切正常。
加载页面时浏览器中的错误消息(初始化 sockjs 连接时):
WebSocket connection to 'ws://my-domain.com/ws/844/blvz89pq/websocket' failed: Error during WebSocket handshake: Unexpected response code: 400
自定义nginx配置的相关部分:
location /ws/ {
proxy_pass http://127.0.0.1:8888;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
来自 nginx.conf 的 $connection_upgrade 的价值:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
如果 Upgrade
header 未设置为 'websocket'
(code),则看起来 tornado-sockjs returns 400。事实上,在第 46 行 if
之前打印 headers 给我们 header Connection=close
的值,并且根本没有 Upgrade
出现。
dict(self.request.headers)
的值
{
"Accept-Language": "en-US,en;q=0.8,ru;q=0.6",
"Accept-Encoding": "gzip, deflate, sdch",
"Sec-Websocket-Key": "*******",
"Connection": "close",
"X-Real-Ip": "172.17.0.1",
"Origin": "http://my-domain.com",
"Sec-Websocket-Extensions": "permessage-deflate; client_max_window_bits",
"X-Forwarded-For": "172.17.0.1",
"Sec-Websocket-Version": "13",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36",
"Host": "my-domain.com",
"X-Forwarded-Proto": "http",
"Cookie": "_ym_uid=1456149826627418608; sessionid=0pn2knqey7raw7w4dst9d7vqvtvsmook; csrftoken=0o1lqSW4XCZvvlvYtN4S7Stt53AyKWf6; __utmx=147844469.bAGHuGeARZy_vppa6db8lg5132382-10:5.mu9KcCiZSDepsLZ385hDXA7448007-11:0; __utmxx=147844469.bAGHuGeARZy_vppa6db8lg5132382-10:1456307221:15552000.mu9KcCiZSDepsLZ385hDXA7458007-11:1457421562:15552000; _ym_isad=0; _ga=GA1.2.2002408319.1456149825; JSESSIONID=dummy",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
}
但是从浏览器检查 headers 显示,连接和升级 headers 都有值,应该对龙卷风有效。
Headers 来自浏览器:
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8,ru;q=0.6
Cache-Control:no-cache
Connection:Upgrade
Cookie:_ym_uid=1456149826627418608; sessionid=0pn2knqey7raw7w4dst9d7vqvtvsmook; __utmx=147844469.bAGHuGeARZy_vppa6db8lg5132382-10:5.mu9KcCiZSDepsLZ385hDXA7448007-11:0; __utmxx=147844469.bAGHuGeARZy_vppa6db8lg5132382-10:1456307221:15552000.mu9KcCiZSDepsLZ385hDXA7448007-11:1457421562:15552000; _ym_isad=0; _ga=GA1.2.2002408319.1456149825; csrftoken=0o1lqSW4XCZvvlvYtN4S7Stt53AyKWf6; JSESSIONID=dummy
Host:my-domain.com
Origin:http://my-domain.com
Pragma:no-cache
Sec-WebSocket-Extensions:permessage-deflate; client_max_window_bits
Sec-WebSocket-Key:/zRJijtAtPjjLNJK49SIDQ==
Sec-WebSocket-Version:13
Upgrade:websocket
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
我可能的建议是 how/when Tornado 解析 headers.
更新:
使用的软件版本:
1. sockjs-tornado==1.0.2
2. tornado==4.3
3. tornado-redis==2.4.18
所以问题出在通过 Docker 容器外的另一个 Nginx 运行 代理请求。
+1 到 Riliam ,但我需要加 5 美分,因为这个问题最近又出现了。
所以要解决这个问题,如果你有 chief nginx 在 nginx powered docker 容器前面,你需要修改你的 chief nginx配置
/etc/nginx/nginx.conf
...
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
...
/etc/nginx/conf.d/virtual-site.conf
8001 – 从 docker 容器公开的端口
location / {
proxy_pass http://127.0.0.1:8001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
问题出在 websocket 连接上,由 nginx 从 tornado/tornado-sockjs 代理到浏览器中的 sockjs 客户端。没有 nginx(在本地主机上)一切正常。
加载页面时浏览器中的错误消息(初始化 sockjs 连接时):
WebSocket connection to 'ws://my-domain.com/ws/844/blvz89pq/websocket' failed: Error during WebSocket handshake: Unexpected response code: 400
自定义nginx配置的相关部分:
location /ws/ {
proxy_pass http://127.0.0.1:8888;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
来自 nginx.conf 的 $connection_upgrade 的价值:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
如果 Upgrade
header 未设置为 'websocket'
(code),则看起来 tornado-sockjs returns 400。事实上,在第 46 行 if
之前打印 headers 给我们 header Connection=close
的值,并且根本没有 Upgrade
出现。
dict(self.request.headers)
{
"Accept-Language": "en-US,en;q=0.8,ru;q=0.6",
"Accept-Encoding": "gzip, deflate, sdch",
"Sec-Websocket-Key": "*******",
"Connection": "close",
"X-Real-Ip": "172.17.0.1",
"Origin": "http://my-domain.com",
"Sec-Websocket-Extensions": "permessage-deflate; client_max_window_bits",
"X-Forwarded-For": "172.17.0.1",
"Sec-Websocket-Version": "13",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36",
"Host": "my-domain.com",
"X-Forwarded-Proto": "http",
"Cookie": "_ym_uid=1456149826627418608; sessionid=0pn2knqey7raw7w4dst9d7vqvtvsmook; csrftoken=0o1lqSW4XCZvvlvYtN4S7Stt53AyKWf6; __utmx=147844469.bAGHuGeARZy_vppa6db8lg5132382-10:5.mu9KcCiZSDepsLZ385hDXA7448007-11:0; __utmxx=147844469.bAGHuGeARZy_vppa6db8lg5132382-10:1456307221:15552000.mu9KcCiZSDepsLZ385hDXA7458007-11:1457421562:15552000; _ym_isad=0; _ga=GA1.2.2002408319.1456149825; JSESSIONID=dummy",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
}
但是从浏览器检查 headers 显示,连接和升级 headers 都有值,应该对龙卷风有效。
Headers 来自浏览器:
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8,ru;q=0.6
Cache-Control:no-cache
Connection:Upgrade
Cookie:_ym_uid=1456149826627418608; sessionid=0pn2knqey7raw7w4dst9d7vqvtvsmook; __utmx=147844469.bAGHuGeARZy_vppa6db8lg5132382-10:5.mu9KcCiZSDepsLZ385hDXA7448007-11:0; __utmxx=147844469.bAGHuGeARZy_vppa6db8lg5132382-10:1456307221:15552000.mu9KcCiZSDepsLZ385hDXA7448007-11:1457421562:15552000; _ym_isad=0; _ga=GA1.2.2002408319.1456149825; csrftoken=0o1lqSW4XCZvvlvYtN4S7Stt53AyKWf6; JSESSIONID=dummy
Host:my-domain.com
Origin:http://my-domain.com
Pragma:no-cache
Sec-WebSocket-Extensions:permessage-deflate; client_max_window_bits
Sec-WebSocket-Key:/zRJijtAtPjjLNJK49SIDQ==
Sec-WebSocket-Version:13
Upgrade:websocket
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
我可能的建议是 how/when Tornado 解析 headers.
更新: 使用的软件版本:
1. sockjs-tornado==1.0.2
2. tornado==4.3
3. tornado-redis==2.4.18
所以问题出在通过 Docker 容器外的另一个 Nginx 运行 代理请求。
+1 到 Riliam
/etc/nginx/nginx.conf
...
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
...
/etc/nginx/conf.d/virtual-site.conf
8001 – 从 docker 容器公开的端口
location / {
proxy_pass http://127.0.0.1:8001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}