Nginx WebSocket代理不断获得HTTP 301重定向

时间:2015-08-10 15:33:56

标签: python curl nginx proxy websocket

我一直试图让Nginx WebSocket代理在过去几天工作,但对于我的生活,我无法让它工作。我遵循了官方指南here并且一直使用Python的websockets模块作为服务器,使用npm包wscat作为客户端。从wscat到Python WebSocket后端的直接连接工作正常(来自浏览器的连接也是如此)。但是一旦我在Nginx中进行分层,它就无法正常工作并继续给我一个标准的HTTP 301重定向。

使用Nginx代理

cURL调试输出:

$ curl 'http://test.ws:8080/websocket' \
> -H 'Pragma: no-cache' \
> -H 'Origin: http://localhost:8080' \
> -H 'Accept-Encoding: gzip, deflate, sdch' \
> -H 'Sec-WebSocket-Version: 13' \
> -H 'Sec-WebSocket-Key: V15bszpaQ+8Vq7mWR6NQbQ==' \
> -H 'User-Agent: Mozilla/5.0' \
> -H 'Upgrade: websocket' \
> -H 'Cache-Control: no-cache' \
> -H 'Connection: Upgrade' \
> -H 'Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits' \
    --compressed -v
* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to test.ws (127.0.0.1) port 8080 (#0)
> GET /websocket HTTP/1.1
> Host: test.ws:8080
> Accept: */*
> Pragma: no-cache
> Origin: http://localhost:8080
> Accept-Encoding: gzip, deflate, sdch
> Sec-WebSocket-Version: 13
> Sec-WebSocket-Key: V15bszpaQ+8Vq7mWR6NQbQ==
> User-Agent: Mozilla/5.0
> Upgrade: websocket
> Cache-Control: no-cache
> Connection: Upgrade
> Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
> 
< HTTP/1.1 301 Moved Permanently
* Server nginx/1.8.0 is not blacklisted
< Server: nginx/1.8.0
< Date: Mon, 10 Aug 2015 15:04:26 GMT
< Content-Type: text/html
< Content-Length: 184
< Location: http://test.ws:8080/websocket/
< Connection: keep-alive
< 
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.8.0</center>
</body>
</html>
* Connection #0 to host test.ws left intact

cURL调试输出没有 Nginx代理:

$ curl 'http://test.ws:8765/' \
> -H 'Pragma: no-cache' \
> -H 'Origin: http://localhost:8080' \
> -H 'Accept-Encoding: gzip, deflate, sdch' \
> -H 'Sec-WebSocket-Version: 13' \
> -H 'Sec-WebSocket-Key: V15bszpaQ+8Vq7mWR6NQbQ==' \
> -H 'User-Agent: Mozilla/5.0' \
> -H 'Upgrade: websocket' \
> -H 'Cache-Control: no-cache' \
> -H 'Connection: Upgrade' \
> -H 'Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits' \
> --compressed -v
* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to test.ws (127.0.0.1) port 8765 (#0)
> GET / HTTP/1.1
> Host: test.ws:8765
> Accept: */*
> Pragma: no-cache
> Origin: http://localhost:8080
> Accept-Encoding: gzip, deflate, sdch
> Sec-WebSocket-Version: 13
> Sec-WebSocket-Key: V15bszpaQ+8Vq7mWR6NQbQ==
> User-Agent: Mozilla/5.0
> Upgrade: websocket
> Cache-Control: no-cache
> Connection: Upgrade
> Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
> 
< HTTP/1.1 101 Switching Protocols
* Server Python/3.4 websockets/2.5 is not blacklisted
< Server: Python/3.4 websockets/2.5
< Upgrade: WebSocket
< Connection: Upgrade
< Sec-WebSocket-Accept: yR97tmHAm9KPEI5vfKiM0/sfTqQ=
^C

我的Nginx(版本1.8.0)配置是这样的(在端口8765上运行在test.ws(127.0.0.1)上的websockets)并且nginx在localhost上的端口8080上进行侦听:

worker_processes  1;

error_log  logs/error.log debug;

events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;

    upstream ws {
        server 127.0.0.1:8765;
    }

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

    server {
        listen       8080;
        server_name  test.ws;

        access_log  logs/localhost.access.log;

        location / {
            root   html;
            index  index.html index.htm;
        }

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

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

}

include servers/*;

任何人都知道我在这里做错了什么,为什么它给我301重定向?

3 个答案:

答案 0 :(得分:2)

事实证明,我的Nginx配置中的根位置节干扰了WebSocket代理传递隧道。有三种方法可以解决这个问题。

  1. 修改根位置节以完全匹配。

    location = / {
        root   html;
        index  index.html index.htm;
    }
    
  2. websocket位置节之后将根位置节重新排序为(首先是特定的节点,最后的节点节点,就像重写匹配规则的工作原理一样)。 / p>

  3. 在Nginx配置中删除以下根位置节将使其正常工作。

    location / {
        root   html;
        index  index.html index.htm;
    }
    

答案 1 :(得分:1)

注意标题。在网络浏览器和客户端发送的标头中,Upgrade不是upgrade

改变这个:

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

    location /websocket/ {
        proxy_pass http://ws;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
    }

注意大写Upgrade

答案 2 :(得分:1)

在我的情况下,它来自客户端,使用路径/ websocket而不是/ websocket /,从而阻止了位置规则的出现。 但是位置顺序的影响是一个很好的提示!