客户环境 Nginx 配置:流式报表与超时排查要点

背景

在客户环境中,Nginx 承担着多重反向代理职责:既负责将 HTTP 访问统一跳转到 HTTPS,又需要将 ORDS 应用、静态资源、图片服务以及 AI 流式报表服务等不同后端能力安全地暴露给终端用户。

当系统从 HTTP 升级到 HTTPS 后,部分用户反馈访问系统或调用流式报表时出现频繁挂起直至超时的问题。这类问题往往不是单一环节造成的------Nginx 的超时参数、后端服务的连接限制、浏览器端的 PWA 行为等,都可能成为请求中断的瓶颈。本文围绕该客户环境的 Nginx 配置展开,梳理各代理路径的职责与关键参数,并给出超时问题的系统排查思路。

01 | 配置职责概览

该 Nginx 配置的核心职责可分为四类:

  1. HTTP 强制跳转 HTTPS:80 端口仅用于重定向,保证所有流量走加密通道。
  2. ORDS 应用代理/ords/ 路径转发至 ORDS 后端,承载核心业务页面。
  3. 静态资源与图片代理/i//images/ 分别代理至静态资源服务和图片服务。
  4. AI 流式报表代理/aireport/ 转发至本地 AI 服务,需支持 WebSocket 与 SSE 长连接。

flowchart TB Client"客户端请求" --> Http"HTTP 80 端口" Http --> Redirect"301 跳转至 HTTPS" Client --> Https"HTTPS 443 端口 / HTTP/2" Https --> Ords"/ords/ 业务应用" Https --> Static"/i/ 静态资源" Https --> Images"/images/ 图片服务" Https --> AI"/aireport/ AI 流式报表" Ords --> OrdsService"ORDS 后端 \[已脱敏IP:8080"] Static --> StaticService"静态资源服务 \[已脱敏IP:8080"] Images --> ImageService"图片服务 localhost:8081" AI --> AIService"AI 报表服务 localhost:10090"

02 | HTTP 统一跳转 HTTPS 与 HTTP/2 配置

核心概念:HTTP/2 与多路复用

HTTP/2 是第二代 HTTP 传输协议,核心特性包括多路复用(Multiplexing)二进制分帧头部压缩。多路复用允许在单个 TCP 连接上并行交错发送多个请求与响应,避免了 HTTP/1.1 中多个请求需排队等待(队头阻塞)的问题,从而显著提升多静态资源并行加载的效率。在 Nginx 中,HTTP/2 作用于客户端与 Nginx 之间的连接链路,后端仍可使用 HTTP/1.1 通信。

配置说明

80 端口仅负责将所有 HTTP 请求以 301 状态码重定向至 HTTPS 地址;HTTPS 主站(443 端口)开启 SSL 与 HTTP/2 支持,并指定 TLS 1.2/1.3 协议与加密套件:

nginx 复制代码
# HTTP 80 端口重定向
server {
    listen 80;
    server_name xyzagent.xyz.com;
    return 301 [已脱敏链接]
}

# HTTPS 443 端口主站
server {
    # 【优化】开启 http2,大幅提升多静态资源并行的加载速度
    listen 443 ssl http2; 
    server_name xyzagent.xyz.com;

    ssl_certificate     /etc/letsencrypt/live/xyzagent.xyz.com/xyz.com.pem;
    ssl_certificate_key /etc/letsencrypt/live/xyzagent.xyz.com/xyz.com.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
}

版本兼容提示listen 443 ssl http2; 为 Nginx 1.25.1 之前的写法;Nginx 1.25.1 及之后版本推荐使用 listen 443 ssl; 配合 http2 on; 指令。

03 | 常规服务反向代理

3.1 ORDS 应用代理(/ords/)

/ords/ 路径代理至 ORDS 后端([已脱敏IP]:8080),承载 APEX 应用页面。配置中透传了主机名、客户端 IP、协议和端口等请求头,使后端能够识别原始访问来源与 HTTPS 协议:

nginx 复制代码
location /ords/ {
    proxy_pass [已脱敏链接]
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-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;
    proxy_set_header X-Forwarded-Port 443;
}

请求头字段说明

请求头 作用
Host 传递原始请求的域名,保证后端虚拟主机路由正确
X-Real-IP 传递客户端真实 IP
X-Forwarded-For 追加客户端 IP 到转发链
X-Forwarded-Proto 标识原始协议为 HTTPS,便于后端生成正确的重定向与绝对链接
X-Forwarded-Port 标识原始端口为 443

3.2 根路径跳转

根路径 / 被配置为 301 跳转至 ORDS 应用首页,确保用户访问域名根地址时能直接进入业务系统:

nginx 复制代码
location / {
    return 301 [已脱敏链接]
}

3.3 静态资源与图片服务

/i/ 路径代理至 ORDS 自带的静态资源目录(APEX 静态文件),/images/ 路径代理至本地图片服务(localhost:8081):

nginx 复制代码
location /i/ {
    proxy_pass      [已脱敏链接]
}

location /images/ {
    proxy_pass      [已脱敏链接]
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

04 | AI 流式报表的关键配置

4.1 流式传输与长连接的核心概念

AI 流式报表服务(/aireport/)与普通 HTTP 请求有本质区别:

  • SSE(Server-Sent Events) :服务端向客户端单向推送实时数据,基于 HTTP 长连接,响应以 text/event-stream 格式分块传输。
  • WebSocket :客户端与服务端双向全双工通信,需通过 HTTP Upgrade 握手升级协议。
  • 分块传输(Chunked Transfer):HTTP/1.1 中服务端无需预先知道响应体长度,可边生成边发送。

若 Nginx 开启代理缓冲(proxy_buffering on),会等后端响应全部到达后才一次性转发给客户端,导致流式数据无法实时推送。因此流式场景必须关闭缓冲。

4.2 配置详解

nginx 复制代码
# AI 流式报表服务
location /aireport/ {
    proxy_pass [已脱敏链接]
    proxy_http_version 1.1;
    
    # 【修改】完美支持 WebSockets 和 SSE 长连接,透传客户端的 Upgrade 和 Connection
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;

    # 【修改】删除了错误的 X-Accel_buffering 和 致命的 chunked_transfer_encoding off
    proxy_buffering off;
    proxy_cache off;
    
    # 【保留】超长超时设置,确保大模型/复杂报表有充足计算时间
    proxy_read_timeout 3600s;
    send_timeout 3600s;
    proxy_connect_timeout 60s;

    tcp_nopush on;
    tcp_nodelay on;
}

关键参数逐项解读

配置项 作用与说明
proxy_http_version 1.1 1.1 长连接与分块传输的基础,HTTP/1.0 不支持 keep-alive 与 chunked
proxy_set_header Upgrade $http_upgrade 动态透传 将客户端的 Upgrade 请求头转发给后端,WebSocket 握手必需
proxy_set_header Connection $http_connection 动态透传 透传连接管理头,兼容 WebSocket 升级与普通长连接
proxy_buffering off 关闭 禁止 Nginx 缓冲后端响应,确保流式数据实时推送
proxy_cache off 关闭 禁止缓存动态流式内容
proxy_connect_timeout 60s 60 秒 Nginx 与后端建立 TCP 连接的超时时间
proxy_read_timeout 3600s 3600 秒 两次连续读取后端响应数据之间的最大等待时间
send_timeout 3600s 3600 秒 Nginx 向客户端发送数据时,两次写操作之间的最大间隔
tcp_nopush on 开启 优化数据包发送,减少小包数量
tcp_nodelay on 开启 禁用 Nagle 算法,降低传输延迟

配置修正说明 :原配置中曾包含 X-Accel-Buffering 响应头设置与 chunked_transfer_encoding off 指令。前者在 Nginx 反向代理场景下无效(该头由后端直接返回时才对 Nginx 生效),后者会强制禁用分块传输编码,反而破坏 SSE 流式响应。两者均已移除。
sequenceDiagram participant C as 客户端 participant N as Nginx (HTTP/2) participant A as AI 流式报表服务 C->>N: 请求 /aireport/ (HTTPS) N->>A: 使用 HTTP/1.1 转发请求及 Upgrade 头 A-->>N: 持续返回流式/分块响应 N-->>C: 关闭缓冲后实时推送到客户端 Note over C,A: 长连接保持,proxy_read_timeout 3600s 兜底

05 | 超时问题排查指南

5.1 Nginx 超时参数全景

当 AI 复杂报表生成耗时较长时,Nginx 侧涉及的三个关键超时参数各有分工:
flowchart LR C客户端 -->|1. 请求| NNginx N -->|2. 建立连接| A后端服务 A -->|3. 响应数据| N N -->|4. 转发数据| C N -. "proxy_connect_timeout<br/>连接建立阶段" .-> A A -. "proxy_read_timeout<br/>等待后端响应" .-> N N -. "send_timeout<br/>等待客户端接收" .-> C

参数 默认值 本配置 超时阶段 典型超时表现
proxy_connect_timeout 60s 60s Nginx 与后端 TCP 连接建立 502 Bad Gateway
proxy_read_timeout 60s 3600s 连接建立后等待后端响应(两次读取间隔) 504 Gateway Timeout
send_timeout 60s 3600s Nginx 向客户端发送数据(两次写间隔) 客户端连接中断

超时机制说明proxy_read_timeout 并非限制后端总处理时间,而是限制两次连续读取之间的最大间隔。只要后端持续有数据产出(即使很慢),连接就不会超时。同理,send_timeout 限制的是向客户端发送数据时两次写操作之间的间隔。

5.2 全链路排查清单

排查提示:若 Nginx 超时参数已调大仍遇到中断超时(如 504 Gateway Timeout 或请求提前断开),排查范围不应仅局限于 Nginx,需按以下链路逐层检查:

  1. 后端服务层 :检查 Gunicorn/Uvicorn/Tomcat/Node.js 等应用容器或网关是否配置了默认超时(如 Gunicorn 的 timeout 默认 30 秒)。
  2. 中间代理层:检查前端 SLB / Cloudflare / 硬件防火墙 / API 网关是否存在较短的连接保活超时或空闲超时。
  3. 数据库层:复杂报表的 SQL 查询是否在数据库端存在执行时间限制。
  4. 浏览器端:检查浏览器是否因 Service Worker 拦截请求导致死锁(详见下文补充说明)。

06 | 注意事项与常见误区

6.1 配置要点

  • HTTP 80 入口仅负责跳转,实际业务由 HTTPS 443 端口承载,开启 HTTP/2 大幅优化了客户端静态资源并发加载。
  • WebSocket 需要 UpgradeConnection 握手报头透传;SSE 主要依赖 HTTP/1.1 + proxy_buffering off
  • 流式响应必须禁用 proxy_buffering,否则数据会堆积在 Nginx 缓冲区,无法即时推送至客户端。
  • proxy_set_header Connection 的值应使用动态变量(如 $http_connection$connection_upgrade),而非固定值 upgrade,否则普通 HTTP 请求也会携带 upgrade 头。

6.2 常见误区

误区 正确理解
proxy_read_timeout 是后端总处理时间上限 实际是两次读取之间的最大间隔,持续有数据则不会超时
开启 proxy_buffering 不影响 SSE 缓冲会导致流式数据延迟推送,必须关闭
配置了 Nginx 超时即可解决所有超时问题 全链路超时需覆盖前端代理、Nginx、后端容器及数据库层
chunked_transfer_encoding off 可加速流式传输 禁用分块传输反而破坏 SSE 流式响应机制

07 | 补充说明:APEX PWA 导致的终端超时

7.1 问题现象

即便完成了上述 Nginx 优化调整,问题仍未彻底解决------同事测试时仍时有超时现象发生。最终联合调试发现,根因并非 Nginx 配置,而是 HTTPS 改造后 APEX PWA(Progressive Web App)导致的终端超时

  • 现象:系统从 HTTP 升级到 HTTPS 后,部分同事的终端浏览器在访问系统或调用流式报表时频繁挂起直至超时。

7.2 根因分析

flowchart TB subgraph 浏览器端 SWService Worker\
PWA 核心脚本
FetchFetch 请求拦截 SW -->|拦截所有请求| Fetch end subgraph 问题链路 HTTPSHTTPS 环境 -->|激活| SW Fetch -->|流式长连接无法处理| Deadlock请求死锁卡死 end subgraph 正常链路 NoSW无 Service Worker --> Direct请求直达 Nginx Direct --> Normal正常响应 end

原因分解

  1. PWA 激活限制:浏览器规定 Service Worker(PWA 核心脚本)仅在 HTTPS 环境下才会生效,HTTP 环境下默认处于休眠/禁用状态。
  2. 前端请求拦截死锁:切到 HTTPS 后,浏览器自动激活了 APEX 默认开启的 PWA,后台的 Service Worker 强制拦截了所有 Fetch 请求。遇到流式长连接(如 AI 流式响应/SSE)时,Service Worker 无法正常处理分块传输,直接将前端请求死锁卡死。

7.3 排查与解决

  • 排查方法 :按 F12 打开开发者工具,在 Application -> Service WorkersConsole 面板中捕获 Service Worker 的拦截与报错信息。
  • 解决方案 :在 APEX **共享组件(Shared Components) -> Progressive Web App ** 中取消 Enable Progressive Web App 的默认勾选,从而关闭 PWA 特性。卸载终端浏览器的 Service Worker 后,请求不再经由 PWA 拦截而直接走 Nginx 代理,超时问题即刻恢复正常。

总结

本文围绕客户环境的 Nginx 配置,梳理了从 HTTP 跳转、HTTP/2 优化到多服务反向代理的完整链路,重点剖析了 AI 流式报表场景下 WebSocket/SSE 长连接的关键配置与超时参数含义。

核心要点回顾

  1. Nginx 层 :HTTP/2 提升并发加载效率;流式场景需关闭 proxy_buffering 并调大 proxy_read_timeoutsend_timeout
  2. 全链路排查:超时问题需逐层检查后端服务、中间代理、数据库及浏览器端,不能只盯 Nginx。
  3. HTTPS 改造的隐藏陷阱:APEX PWA 在 HTTPS 下自动激活,Service Worker 拦截流式请求导致死锁,需在 APEX 中关闭 PWA 特性。

行动建议:若客户环境再次出现类似超时问题,建议按"浏览器开发者工具 → Nginx 错误日志 → 后端服务日志 → 中间链路设备"的顺序逐层排查,优先确认是否存在 Service Worker 拦截,再检查各层超时配置是否匹配。