Nginx之websocket配置

时间:2025-02-20 18:24:09

在 Nginx 配置中,map $http_upgrade $connection_upgrade 主要用于 WebSocket 代理,以确保正确处理 Upgrade 头部,实现 WebSocket 连接。以下是完整的 Nginx 配置示例:


完整配置示例(WebSocket 代理)

http {
    # 定义一个变量 $connection_upgrade
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    server {
        listen 80;
        server_name example.com;

        location /ws/ {
            proxy_pass http://backend_server;
            proxy_http_version 1.1; # WebSocket 需要 HTTP/1.1
            proxy_set_header Upgrade $http_upgrade;  # 传递 Upgrade 头
            proxy_set_header Connection $connection_upgrade;  # 传递 Connection 头
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

参数解析

  1. map $http_upgrade $connection_upgrade
  • 该指令将 Upgrade 头部映射到 Connection 头部:
  • 如果 $http_upgrade 变量有值(比如 websocket),$connection_upgrade 设为 upgrade
  • 如果 $http_upgrade 为空,则设为 close
  1. proxy_pass http://backend_server;
  • 代理请求到后端 WebSocket 服务器。
  1. proxy_http_version 1.1;
  • WebSocket 需要 HTTP/1.1 支持,必须指定。
  1. proxy_set_header Upgrade $http_upgrade;
  • 传递 Upgrade 头部,以保持 WebSocket 连接。
  1. proxy_set_header Connection $connection_upgrade;
  • 传递 Connection 头部,确保 WebSocket 代理正确处理升级请求。

$http_upgrade 变量的值来自 HTTP 请求头中的 Upgrade 头部,它用于指示客户端希望升级的协议类型。常见的值包括:

1. WebSocket 连接

当浏览器或客户端请求 WebSocket 连接时,HTTP 请求头通常包含:

Upgrade: websocket
Connection: Upgrade

此时,在 Nginx 配置中,$http_upgrade 变量的值为:

websocket

在 Nginx 配置中:

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

这里的 '' close; 并不是直接关闭连接的意思,而是设置 Connection 头的值为 "close",告诉客户端和服务器在当前请求处理完成后不要保持连接。

含义解析

  • $http_upgrade 为空(即请求没有 Upgrade 头):
proxy_set_header Connection $connection_upgrade;

这相当于:

proxy_set_header Connection "close";

这意味着 Nginx 会在响应后关闭连接(不复用 HTTP 连接),但不会主动断开连接或拒绝请求

  • $http_upgrade 有值(如 websocket):
proxy_set_header Connection "upgrade";

这允许 HTTP 连接升级到 WebSocket 等协议。


普通 HTTP 请求的情况

如果是普通的 HTTP 请求(如浏览器访问网页),通常不会包含 Upgrade 头部,因此:

  • $http_upgrade 为空(''
  • $connection_upgrade 设为 "close"
  • 服务器会处理 HTTP 请求并正常返回响应
  • 但 Nginx 会在响应后关闭连接,而不会保持 Keep-Alive 连接

是否会影响普通 HTTP 请求?

不会影响 HTTP 请求的正常处理,普通 HTTP 请求仍然会被 Nginx 正常响应。唯一的区别是:

  • Connection: close响应后关闭连接
  • Connection: keep-alive响应后保持连接(若启用 keepalive

如果你希望在普通 HTTP 请求中也保持连接,可以修改 map 规则:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      keep-alive;
}

这样,普通 HTTP 请求的 Connection 头就会被设为 keep-alive,从而避免每次请求都重新建立 TCP 连接,提高性能。


总结

  1. Connection: close 不会直接关闭连接,而是响应后不复用连接
  2. map 语句不会影响请求的正常处理,只是修改 Connection 头的行为。
  3. 可以改成 keep-alive,让普通 HTTP 请求保持连接,提高性能。


WebSocket 本身就是一种长连接。它与传统的 HTTP 连接不同,允许服务器和客户端之间进行全双工通信,而不需要客户端频繁发送请求来保持连接。


1. WebSocket 为什么是长连接?

WebSocket 连接的生命周期如下:

  1. 客户端发起 WebSocket 握手
  • 通过 HTTP/1.1 的 Upgrade 头进行协议升级:
GET /ws HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
  • 服务器响应:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
  • 连接升级后,通信协议从 HTTP 切换为 WebSocket。
  1. 保持连接
  • 连接建立后,WebSocket 不会像普通 HTTP 请求一样在响应后立即关闭
  • 服务器和客户端可以相互发送消息,并且消息可以是双向的(全双工通信)。
  • 连接会一直保持,直到客户端或服务器主动关闭。
  1. 连接关闭
  • WebSocket 连接可以在任意一方调用 close() 方法后关闭:
  • 客户端主动关闭 (ws.close())
  • 服务器主动关闭
  • 连接超时、网络异常等

2. WebSocket vs. HTTP 连接

HTTP(短连接)

WebSocket(长连接)

通信方式

请求-响应模式(客户端发请求,服务器返回数据)

双向通信(客户端和服务器都能主动发送消息)

连接状态

一次请求完成后通常关闭连接

连接保持直到显式关闭

延迟

需要每次建立 TCP 连接

一次握手后持续使用,低延迟

适用场景

普通网页访问、API 请求

实时聊天、gupiao行情、在线游戏等


3. WebSocket 是否需要 Connection: keep-alive

不需要!

  • HTTP 的 keep-alive 主要用于 复用 TCP 连接,减少每次请求的握手开销。
  • WebSocket 连接建立后,本身就是 持久连接,不需要 keep-alive
  • WebSocket 协议升级后,HTTP 头部(如 keep-alive)不再适用。

4. WebSocket 代理中的 map 规则

在 Nginx 配置 WebSocket 代理时,通常使用:

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

这里:

  • WebSocket 连接的 Upgrade: websocket 头部会使 Connection: upgrade,保持 WebSocket 连接。
  • 普通 HTTP 请求没有 Upgrade 头,因此 Connection: close,表示请求完成后关闭连接(短连接)。
  • WebSocket 不依赖 keep-alive,它是天然的长连接

5. 什么时候 WebSocket 可能会断开?

尽管 WebSocket 是长连接,但以下情况可能导致断开:

  1. 服务器或客户端主动关闭
  • 服务器调用 ws.close()
  • 客户端调用 websocket.close()
  1. 网络异常
  • 断网、超时、IP 变更等
  1. 代理/防火墙干预
  • 一些代理服务器或防火墙可能会在一段时间内关闭空闲 WebSocket 连接。
  • 解决方案:
  • 心跳机制:定期发送 ping 数据包
  • 设置 Nginx proxy_read_timeout
location /ws/ {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_read_timeout 3600s;  # 避免超时
}

总结

✅ WebSocket 本质上是长连接,在连接建立后可以持续通信,直到主动关闭或发生网络问题。
不需要 keep-alive,因为 WebSocket 连接本身就是持久的。
✅ 需要处理可能的网络断开、代理超时等情况,以确保连接稳定。

你是遇到 WebSocket 连接被断开的情况,还是想优化 WebSocket 代理?

nginx 这些配置参数是否会影响websocket的长连接?

keepalive_timeout 65 ;

proxy_connect_timeout 300;

proxy_send_timeout 300;

proxy_read_timeout 300;

是的,这些 Nginx 配置参数会影响 WebSocket 长连接的稳定性,具体影响如下:


1. keepalive_timeout 65;

  • 作用
  • 适用于 HTTP 连接,控制客户端空闲连接在关闭前的最大等待时间(秒)。
  • 如果客户端在 keepalive_timeout 时间内没有新请求,Nginx 关闭该连接。
  • 对 WebSocket 的影响
  • WebSocket 连接不受 keepalive_timeout 影响,因为 WebSocket 是升级后的持久连接,而 keepalive_timeout 仅影响 HTTP keep-alive 连接。
  • 无影响,但如果你的 WebSocket 应用有 HTTP 轮询(long polling),该参数可能会影响 HTTP 连接的持久性。

结论:对 WebSocket 无影响,主要影响普通 HTTP 长连接。


2. proxy_connect_timeout 300;

  • 作用
  • 控制 Nginx 连接到后端服务器的超时时间(单位:秒)。
  • 如果在 proxy_connect_timeout 时间内无法建立 TCP 连接(比如后端服务器响应慢),Nginx 将返回错误。
  • 对 WebSocket 的影响
  • 仅影响 WebSocket 连接的初始建立阶段(握手阶段)。
  • 不会影响已建立的 WebSocket 连接
  • 适用于后端服务器延迟较高的情况(如 WebSocket 服务器启动较慢)。

结论:仅影响 WebSocket 连接建立,不影响已建立的长连接。


3. proxy_send_timeout 300;

  • 作用
  • 控制 Nginx 向后端服务器发送数据的超时时间(单位:秒)。
  • 如果 Nginx 在 proxy_send_timeout 时间内未能成功向后端发送完整的数据包,则连接会被关闭。
  • 对 WebSocket 的影响
  • WebSocket 服务器通常需要持续发送数据,如果 300 秒内没有任何数据发送,Nginx 可能会关闭 WebSocket 连接。
  • 适用于控制长时间无数据发送的 WebSocket 连接,但通常 WebSocket 服务器会发送心跳包避免超时。

⚠️ 建议修改:如果 WebSocket 连接需要长时间保持,增大 proxy_send_timeout,比如:

proxy_send_timeout 3600s;  # 1小时

结论:影响 WebSocket 长时间无数据发送的情况,建议增加超时时间或实现心跳机制。


4. proxy_read_timeout 300;

  • 作用
  • 控制 Nginx 从后端服务器读取数据的超时时间(单位:秒)。
  • 如果 Nginx 在 proxy_read_timeout 时间内未能收到来自后端的任何数据,Nginx 会关闭连接。
  • 对 WebSocket 的影响
  • 如果 WebSocket 连接在 300 秒内没有收到任何消息,Nginx 可能会断开连接
  • 适用于 WebSocket 服务器的长时间无数据传输的情况
  • 解决方法:
  • 增加超时时间,比如:
proxy_read_timeout 3600s;  # 1小时
  • 使用 WebSocket 心跳(ping/pong),让服务器定期发送 ping,确保连接保持活跃。

⚠️ 建议修改:如果 WebSocket 需要长期连接,建议增大 proxy_read_timeout,避免意外断开。

结论:影响 WebSocket 长时间无数据接收的情况,建议增加超时时间或使用心跳包。


最佳 WebSocket 配置(优化长连接)

server {
    listen 80;
    server_name example.com;

    location /ws/ {
        proxy_pass http://backend_server;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        
        proxy_connect_timeout 10s;    # 连接后端服务器超时
        proxy_send_timeout 3600s;     # 发送数据超时
        proxy_read_timeout 3600s;     # 读取数据超时
        send_timeout 3600s;           # 发送超时(客户端)
    }
}

总结

参数

默认值

作用

对 WebSocket 的影响

优化建议

keepalive_timeout

65s

控制 HTTP keep-alive 连接超时

无影响

无须更改

proxy_connect_timeout

60s

连接后端 WebSocket 服务器超时

仅影响连接建立

可调小,如 10s

proxy_send_timeout

60s

向后端发送数据超时

影响长时间无数据发送

增大,如 3600s

proxy_read_timeout

60s

从后端读取数据超时

影响长时间无数据接收

增大,如 3600s

???? 重点优化

  • proxy_read_timeoutproxy_send_timeout 需要足够大,防止 WebSocket 连接因超时断开。
  • WebSocket 服务器定期发送心跳包(ping/pong),保证连接存活。
  • keepalive_timeout 不影响 WebSocket,可忽略。