Nginx 反向代理 WebSocket 超时 [英] Nginx Reverse Proxy WebSocket Timeout

查看:525
本文介绍了Nginx 反向代理 WebSocket 超时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 wowza 应用程序中使用 java-websocket 来满足我的 websocket 需求,并将 nginx 用于 ssl,将请求代理到 java.

I'm using java-websocket for my websocket needs, inside a wowza application, and using nginx for ssl, proxying the requests to java.

问题是连接似乎在 1 小时后被切断,服务器端.客户端甚至不知道它已经断开连接了很长时间.我不想只调整 nginx 上的超时,我想了解连接被终止的原因,因为套接字会像往常一样运行,直到它不是.

The problem is that the connection seems to be cut after exactly 1 hour, server-side. The client-side doesn't even know that it was disconnected for quite some time. I don't want to just adjust the timeout on nginx, I want to understand why the connection is being terminated, as the socket is functioning as usual until it isn't.

忘记贴配置了:

location /websocket/ {
    proxy_set_header        X-Real-IP       $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    include conf.d/proxy_websocket;
    proxy_connect_timeout 1d;
    proxy_send_timeout 1d;
    proxy_read_timeout 1d;
}

这包括配置:

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass                      http://127.0.0.1:1938/;

  • Nginx/1.12.2
  • CentOS Linux 版本 7.5.1804(核心)
  • Java WebSocket 1.3.8(GitHub)
  • 推荐答案

    超时可能来自客户端、nginx 或后端.当你说它被服务器端"切断时,我认为这意味着你已经证明它不是客户端.您的 nginx 配置看起来不应该超时 1 天,因此只剩下后端.

    The timeout could be coming from the client, nginx, or the back-end. When you say that it is being cut "server side" I take that to mean that you have demonstrated that it is not the client. Your nginx configuration looks like it shouldn't timeout for 1 day, so that leaves only the back-end.

    我的第一个建议是,您尝试直接连接到后端并确认问题仍然存在(出于故障排除目的,将 nginx 从图片中移除).请注意,如果使用浏览器不切实际,您可以使用诸如 curl 之类的命令行实用程序来执行此操作.这是一个示例测试命令:

    My first suggestion is that you try connecting directly to the back-end and confirm that the problem still occurs (taking nginx out of the picture for troubleshooting purposes). Note that you can do this with command line utilities like curl, if using a browser is not practical. Here is an example test command:

    time curl --trace-ascii curl-dump.txt -i -N \
      -H "Host: example.com" \
      -H "Connection: Upgrade" \
      -H "Upgrade: websocket" \
      -H "Sec-WebSocket-Version: 13" \
      -H "Sec-WebSocket-Key: BOGUS+KEY+HERE+IS+FINE==" \
      http://127.0.0.1:8080
    

    在我的(工作)案例中,运行上面的示例无限期地保持打开状态(我手动停止了 Ctrl-C),因为 curl 和我的服务器都没有实现超时.但是,当我将其更改为通过 nginx 作为代理(默认超时为 1 分钟)时,如下所示,我在几乎刚好 1 分钟后看到来自 nginx 的 504 响应.

    In my (working) case, running the above example stayed open indefinitely (I stopped with Ctrl-C manually) since neither curl nor my server was implementing a timeout. However, when I changed this to go through nginx as a proxy (with default timeout of 1 minute) as shown below I saw a 504 response from nginx after almost exactly 1 minute.

    time curl -i -N --insecure \
      -H "Host: example.com" \
      https://127.0.0.1:443/proxied-path
    

    HTTP/1.1 504 Gateway Time-out
    Server: nginx/1.14.2
    Date: Thu, 19 Sep 2019 21:37:47 GMT
    Content-Type: text/html
    Content-Length: 183
    Connection: keep-alive
    
    <html>
    <head><title>504 Gateway Time-out</title></head>
    <body bgcolor="white">
    <center><h1>504 Gateway Time-out</h1></center>
    <hr><center>nginx/1.14.2</center>
    </body>
    </html>
    
    real    1m0.207s
    user    0m0.048s
    sys 0m0.042s
    

    其他想法

    有人提到尝试 proxy_ignore_client_abort但这应该没有任何区别,除非客户端关闭连接.此外,虽然这可能会使内部连接保持打开状态,但我认为它无法保持端到端流的完整性.

    Other ideas

    Someone mentioned trying proxy_ignore_client_abort but that shouldn't make any difference unless the client is closing the connection. Besides, although that might keep the inner connection open I don't think it is able to keep the end-to-end stream intact.

    您可能想尝试proxy_socket_keepalive,尽管这需要 nginx >= 1.15.6.

    You may want to try proxy_socket_keepalive, though that requires nginx >= 1.15.6.

    最后,WebSocket 代理文档中有一条提示,提示一个很好的解决方案:

    Finally, there's a note in the WebSocket proxying doc that hints at a good solution:

    或者,可以将代理服务器配置为定期发送 WebSocket ping 帧以重置超时并检查连接是否仍然有效.

    Alternatively, the proxied server can be configured to periodically send WebSocket ping frames to reset the timeout and check if the connection is still alive.

    如果您可以控制后端并希望连接无限期地保持打开状态,请定期发送 "ping" 帧到客户端(假设使用 Web 浏览器,则客户端不需要更改,因为它是作为规范的一部分实现的)应该阻止无论连接打开多长时间或涉及多少个中间盒,连接都不会因不活动而关闭(使 proxy_read_timeout 变得不必要).

    If you have control over the back-end and want connections to stay open indefinitely, periodically sending "ping" frames to the client (assuming a web browser is used then no change is needed on the client-side as it is implemented as part of the spec) should prevent the connection from being closed due to inactivity (making proxy_read_timeout unnecessary) no matter how long it's open or how many middle-boxes are involved.

    这篇关于Nginx 反向代理 WebSocket 超时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆