bigywater.tech
常见报错 · 35

Nginx 504 Gateway Time-out:proxy_read_timeout 是读间隔不是总时长,GET 超时会换上游重试而 POST 不会,默认 60 s 实测

“504 Gateway Time-out” 常见的建议是加大 proxy_read_timeout。这篇在本机起自己的 nginx 和故意很慢的上游,把超时发生在响应头阶段还是响应体阶段、超时到底是总时长还是读间隔、GET 与 POST 的重试差别,以及默认值各测了一遍。

60.0 s
不写 proxy_read_timeout 时,上游 70 s 才回,实测得到 504 的耗时
4.03 s
proxy_read_timeout 只有 1 s,但上游每 0.5 s 吐一个字节、总共 4 s 的响应,仍完整返回 200(超时是读间隔不是总时长)
200 / 504
两台上游一台慢时,连发 POST 的结果交替出现;GET 因为会换下一台重试而始终拿到 200

504 怎么来的

实测 · 本机执行输出
  客户端:HTTP 504,页面标题 "504 Gateway Time-out",等了 1.02 s
      error.log: [error] *2 upstream timed out (60: Operation timed out) while reading response header from upstream, request: "GET /slow HTTP/1.1", upstream: "http://127.0.0.1:9791/slow", host: "127.0.0.1:9780"
  access.log: 127.0.0.1 - - [29/Oct/2026:15:19:08 +0800] "GET /slow HTTP/1.1" 504 167 "-" "Python-urllib/3.14"

nginx 等上游的响应头超过 proxy_read_timeout;error.log 写明阶段。

超时的含义

实测 · 本机执行输出
  trickle(总共约 4 s,每次间隔 0.5 s):HTTP 200,收到 8 字节,总耗时 4.03 s
  stall(发了 4 字节后停住):HTTP None,收到的内容 'IncompleteRead: IncompleteRead(0 bytes read, 100 more expect',耗时 1.00 s
      error.log: [error] *4 upstream timed out (60: Operation timed out) while reading upstream, request: "GET /stall HTTP/1.1", upstream: "http://127.0.0.1:9793/stall", host: "127.0.0.1:9780"

是两次读之间的间隔,不是整个响应的总时长。

响应体阶段超时

实测 · 本机执行输出
  (上面第 1 步是前者;stall 的情形是后者,见上面 error.log)

响应头已发给客户端,之后超时只会让连接被切断,不是 504。

GET 与 POST

实测 · 本机执行输出
  GET:HTTP 200 "second upstream",耗时 1.01 s
      error.log: [error] *2 upstream timed out (60: Operation timed out) while reading response header from upstream, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:9794/", host: "127.0.0.1:9780"
  接着连发 4 次 POST(轮询,max_fails=0 所以慢的那台不会被摘掉,每隔一次落在它上面):[(200, 0.0), (504, 1.0), (200, 0.0), (504, 1.0)]

多台上游时 GET 超时会换下一台重试,POST 默认不重试。

默认值与调整

实测 · 本机执行输出
  不写 proxy_read_timeout(上游 70 s):HTTP 504,耗时 60.0 s
      error.log: [error] *2 upstream timed out (60: Operation timed out) while reading response header from upstream, request: "GET /default HTTP/1.1", upstream: "http://127.0.0.1:9796/default", host: "127.0.0.1:9780"
  proxy_read_timeout 5s(上游 3 s):HTTP 200 "slow ok",耗时 3.01 s

默认 60 s;对慢接口单独调大,而不是全局。

分步演示

网关超时
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64;报错文本都是真实复现时原样捕获的(命令行工具统一用 LC_ALL=C 取英文原文,路径换成 );所有服务都是本机上自己起的、只监听 127.0.0.1,不访问外网;计时用 time.perf_counter,数字每次运行会有小幅抖动。本篇用 nginx/1.31.7(Homebrew);每个实验起一个自己的 nginx(自己的前缀目录与配置,只监听 127.0.0.1:9780),上游是 Python 脚本里起的故意很慢的小服务;errno 编号 60 是 macOS 上的
    • 没有验证:proxy_connect_timeout 与 proxy_send_timeout(本篇试图用监听队列占满和不读请求的上游触发,在这台机器上没有得到可以解释的结果,所以没有写进正文);fastcgi_read_timeout、uwsgi_read_timeout、grpc_read_timeout 等同类指令;Linux 上 error.log 的编号(110);proxy_next_upstream 对 non_idempotent 的开关;nginx 前面还有负载均衡器或 CDN 时它们自己的超时;客户端(浏览器、curl)自己的超时
    京ICP备2026067502号-1京公网安备11010502063487号