Nginx websocket 将适用于单个响应或根本不适用,似乎是随机的

Posted

技术标签:

【中文标题】Nginx websocket 将适用于单个响应或根本不适用,似乎是随机的【英文标题】:Nginx websocket will work for a single response or not at all, seemly at random 【发布时间】:2020-10-30 19:16:40 【问题描述】:

我一直在通过 nginx 在 Asp.net core 3 上使用 SignalR 来将 Unity3d 应用程序联网。在我通过 Kestral 进行的本地构建中,websockets 工作得很好。但是,一旦我通过 Nginx 代理我的 WebApp,我的 websocket 将用于单个响应或根本不工作,似乎是随机的。想法?

我当前的 nginx 构建配置:

server 
        listen 80;
        server_name ip domain.com www.domain.com;
        return 301 https://$host$request_uri;


server 

        listen 443 ssl http2;
        server_name ip domain.com www.domain.com;

        # SSL Configuration
        ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        #make sure to check for more up to date ciphers
        ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
        root /var/www/html;

        location / 
                proxy_pass http://localhost:5000;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection keep_alive;
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;

                proxy_set_header  X-Real-IP          $remote_addr;
                proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header   X-Forwarded-Proto $scheme;

        


        location /notifications 

                proxy_pass http://localhost:5000/notifications/;
                include             /etc/nginx/proxy_params;
                proxy_http_version 1.1;
                set $http_upgrade "websocket";
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
                proxy_buffering off;
                proxy_read_timeout 3600;

                proxy_headers_hash_max_size 512;
                proxy_headers_hash_bucket_size 128;
                proxy_set_header   X-Real-IP $remote_addr;
                proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header   X-Forwarded-Host $host:$server_port;
                proxy_set_header   X-Forwarded-Proto $scheme;

                proxy_buffers 8 32k;
                proxy_buffer_size 64k;
       

        location ~^/identity 
                rewrite ^/identity/login? /login/ break;
                proxy_pass http://localhost:5050;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection keep-alive;
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
        


【问题讨论】:

嗨@re-fuse,写第一篇文章并不容易。在我看来,您可能需要考虑向社区提供更多信息,而不仅仅是粘贴配置文件。例如,当您说它随机工作时,您可能会提供更多详细信息。此外,您可能需要说明您已经尝试解决的问题。 @RonaldRink'd-fens' 嘿!感谢您的答复。我在下面添加了一个答案。这是下划线 Nginx 行为的问题。这种行为在早期版本中不存在,因为我的代理设置在这篇文章之前有效。让我相信这是最近的行为更新。 【参考方案1】:

问题: 启用 signalr 的调试日志后,我发现我的 websocket 被降级到 HTTP 1.0,这解释了为什么我在使用 websockets 时只收到一次或全部来自服务器的响应。

我的应用程序(Unity Game)支持这两种协议,如果您查看我的配置,您会发现分别配置为 HTTP 和 Websockets 的“location /”块和“location /notifications”块。我的应用程序使用 http 进行身份验证,使用 websockets 来实际玩游戏。因此,Nginx 在通过 http 进行身份验证后保留了原始的 http 代理标头,然后调用“/notifications”端点,尽管它是为 websockets 设置的(我期望的行为是基于我要创建的配置的新 websocket 连接)。

修复: 我更改了“location/”(我的常规 http 端点)块标头以支持 HTTP 1.1,如下所示:

    location / 
            proxy_pass http://localhost:5000;
            proxy_http_version 1.1;

            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;

            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;

            proxy_set_header  X-Real-IP          $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Proto $scheme;

    

根据 asp.net 核心文档清理 websocket 块:

    location /notifications 

            proxy_pass http://localhost:5000/notifications/;
           # include             /etc/nginx/proxy_params;
            proxy_http_version 1.1;
            # Configure WebSockets
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            #proxy_cache_bypass $http_upgrade;
            proxy_cache off;

            # Configure ServerSentEvents
            proxy_buffering off;

            # Configure LongPolling
            proxy_read_timeout 100s;
        

           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-Forwarded-Proto $scheme;
   

在此编辑之后,我的 HTTP 和 websocket 端点都按预期工作。我不确定为什么标头会保留在 websocket“位置/通知”块中,但我确信某处有一些细微的 Nginx 文档。

希望这对将来的某人有所帮助。

【讨论】:

以上是关于Nginx websocket 将适用于单个响应或根本不适用,似乎是随机的的主要内容,如果未能解决你的问题,请参考以下文章

Websocket 适用于 EC2 url,但不适用于 ElasticBeanstalk URL

docker 中的 nginx + websocket 代理 + Ratchet

适用于 Android 和 iOS 的基于 websocket 的 MQTT

nginx 反向代理 websockets

uniapp中websocket的使用(一)适用页面只会存在单个长连接

Websockets 与主要应用程序(nginx + 乘客 + faye)