Nginx connection与request本质区别:高并发稳定性的底层密码
2026/6/16 8:25:00 网站建设 项目流程

1. 项目概述:为什么搞懂 connection 和 request 是 Nginx 真正上手的分水岭

刚接触 Nginx 的人,往往卡在“配得通但跑不稳”“压测一上就崩”“日志里全是 502/504 却查不到源头”这类问题上。我带过不少运维和后端新人,发现一个共性:他们能熟练写location、配proxy_pass、加gzip on,但一问“请求进来时,Nginx 到底先做了什么?”“为什么加了keepalive_timeout 65,客户端却只维持了 15 秒?”“worker_connections 1024是指每个 worker 能处理 1024 个请求,还是 1024 个连接?”——答案就开始模糊、矛盾,甚至查文档也绕晕。这说明,他们还没真正踩进 Nginx 的底层运行逻辑里。而这个逻辑的起点,就是connection(连接)request(请求)这两个最基础、却最容易被混淆的概念。它们不是语法糖,而是 Nginx 架构设计的双基石:connection 是 TCP 层的资源实体,是操作系统内核分配的 socket 句柄;request 是 HTTP 层的语义单元,是基于 connection 发起的一次完整 HTTP 交互。Nginx 的高性能,恰恰来自它对 connection 的极致复用(避免频繁建连/断连开销)和对 request 的高效调度(多路复用、事件驱动)。你调worker_processes auto,本质是在争抢 CPU 核心来管理 connection;你设client_header_timeout 60,其实是在给 connection 上等待 request header 的时间设限;你看到 access_log 里每行一条记录,那不是一次 connection 的日志,而是一次 request 的快照。这篇笔记,不讲怎么部署、不贴配置模板,专攻这两个概念的物理存在、生命周期、相互关系、以及它们如何真实影响你的服务稳定性、并发能力和排障效率。适合所有已经能写基本配置、但想把 Nginx 从“会用”推进到“懂原理”的人——尤其是那些正在排查超时、连接数打满、上游响应慢却找不到根因的工程师。

2. 核心设计解析:Nginx 如何用 connection 和 request 构建高并发模型

2.1 从单线程阻塞到多进程事件驱动:connection 管理的演进逻辑

很多人以为 Nginx 是“多线程”,这是典型误解。Nginx 采用的是master-worker 多进程 + epoll/kqueue 事件驱动模型。理解这一点,是理解 connection 管理的前提。我们先看传统 Apache 的 prefork 模式:每个请求 fork 一个子进程,每个子进程独占一个 connection,处理完即销毁。好处是隔离性好,坏处是进程创建销毁开销大,内存占用高,连接数上来后系统负载飙升。Nginx 完全反其道而行之:master 进程只做管理工作(读配置、启停 worker、平滑升级),真正的干活的是多个 worker 进程。每个 worker 进程启动时,就通过worker_connections参数向操作系统申请一批可用的 socket 连接句柄(即 connection 资源池)。注意,这个池子里的 connection 数量,是该 worker 进程能同时维持的最大 TCP 连接数,不是请求数。比如worker_connections 1024,意味着一个 worker 最多能同时 hold 住 1024 个 TCP 连接。这些 connection 一旦建立,就不会轻易关闭——Nginx 默认开启keepalive,只要客户端支持,同一个 connection 就可以承载多个 request(HTTP/1.1 默认 keep-alive,HTTP/2 原生多路复用)。这就引出了第一个关键设计思想:connection 是昂贵的、需要复用的底层资源;request 是轻量的、可批量调度的业务单元。Nginx 的事件循环(event loop)就像一个高效的交通调度员:它不主动去“处理”请求,而是监听所有已注册 connection 的状态变化(如EPOLLIN表示有数据可读,EPOLLOUT表示可写)。当某个 connection 上有新数据到来,事件循环立刻捕获,然后将这个 connection 关联的 request 解析出来,交给对应的 handler(比如ngx_http_core_module)去执行具体的 location 匹配、变量替换、upstream 转发等逻辑。整个过程不阻塞,一个 worker 进程靠一个单线程就能轮询成千上万个 connection,这就是它能轻松支撑数万并发连接的核心秘密。你调worker_processes auto,其实是让 Nginx 自动匹配 CPU 核心数,确保每个 worker 都能独占一个核心,避免进程切换开销;你设worker_rlimit_nofile 65535,则是为每个 worker 进程提升文件描述符上限,因为每个 connection 都要消耗一个 fd。这些参数背后,全是围绕“如何更高效地管理和复用 connection”这一目标展开的。

2.2 request 的生命周期:从 TCP 握手完成到响应发送完毕的七步拆解

如果说 connection 是高速公路,那么 request 就是高速公路上行驶的每一辆车。一辆车(request)的完整旅程,决定了你的业务是否能被正确、及时地送达。Nginx 中一个 request 的生命周期,严格遵循 HTTP 协议规范,并被划分为七个清晰阶段(phases),每个阶段都有对应的 handler 链。这不是理论抽象,而是你写ifrewriteauth_request等指令时,它们实际生效的位置。我们以一个典型的反向代理场景为例,走一遍全过程:

  1. Post-read phase(读取后):TCP 连接建立后,Nginx 从 socket 缓冲区读取 client 发来的原始字节流。此时 request 还未被解析,只是 raw data。realip模块在此阶段修改$remote_addr,用于获取真实 IP。
  2. Server-rewrite phase(server 级重写):Nginx 开始解析 HTTP 请求行(如GET /api/user?id=123 HTTP/1.1)和请求头(headers)。server_name匹配、listen端口判断都在此阶段完成。rewrite指令如果写在server块里,就在此执行。
  3. Find-config phase(配置查找):根据解析出的 URI(如/api/user),Nginx 开始遍历所有location块,进行最长前缀匹配或正则匹配,最终确定该 request 应该由哪个location块处理。这是路由的核心,也是性能敏感点——location 写得太深、正则太多,这里就会变慢。
  4. Rewrite phase(location 级重写):进入匹配到的location后,执行该块内的rewrite指令。注意,rewrite ... last会触发新一轮的 find-config,而rewrite ... break则直接跳出,不再重新匹配。这是新手最容易混淆的点。
  5. Post-rewrite phase(重写后):检查上一步是否有内部跳转(internal redirect),如果有,则重新进入 find-config 阶段;如果没有,则继续向下。
  6. Preaccess phase(访问前):执行访问控制前的准备工作,比如limit_req(限流)、limit_conn(限连接)模块在此阶段介入。如果你配置了limit_req zone=one burst=5 nodelay,Nginx 就会在这里检查当前 connection 或 request 是否超出速率限制。
  7. Access phase(访问控制):真正的权限校验,如auth_basic(基础认证)、allow/deny(IP 白名单)、auth_request(子请求鉴权)。只有通过这里,request 才能进入 content phase。
  8. Content phase(内容生成):这是业务逻辑的主战场。proxy_passfastcgi_passreturnecho等指令都在此阶段执行。Nginx 会根据配置,将 request 转发给 upstream server,或者直接返回静态文件、自定义响应体。
  9. Log phase(日志记录):request 处理完毕,无论成功失败,Nginx 都会在此阶段将$status$upstream_status$request_time等变量写入 access_log。注意,$request_time记录的是从 Nginx 接收到第一个字节到发送完最后一个字节的总耗时,包含了 upstream 处理时间;而$upstream_response_time只记录 upstream 返回第一个字节的时间。这两个值的差,就是 Nginx 自身处理和网络传输的时间。

这九个阶段(官方文档常列为 11 个,但核心是这九个)构成了 request 的完整生命线。你写的每一行配置,都锚定在某个特定阶段。理解这个链条,你就知道为什么rewrite放在location外无效,为什么limit_req必须放在serverlocation块顶层,为什么auth_request一定要配合error_page 401使用。它不是黑盒,而是一个可追踪、可干预、可调试的精密流水线。

2.3 connection 与 request 的数量关系:一张表看懂并发瓶颈真相

connection 和 request 的数量关系,是压测和线上排障中最容易误判的点。很多人看到监控里 “connections: 5000” 就慌了,以为马上要打满;或者看到 “requests per second: 2000” 就觉得并发很高,却忽略了背后的 connection 消耗。下面这张表,是我在线上环境实测并反复验证过的典型比例关系,它揭示了不同场景下二者的真实映射:

场景描述典型 connection 数典型 request 数/秒connection:request 比例关键影响因素实测备注
HTTP/1.1 + Keep-Alive(浏览器默认)100050001:5keepalive_timeout、客户端行为、upstream响应速度浏览器会复用 connection,一个 connection 可承载 5~10 个 request,取决于页面资源数和 timeout 设置
HTTP/1.1 + 短连接(curl -H "Connection: close")500050001:1客户端强制关闭每个 request 都新建 connection,fd 消耗极大,极易打满worker_connections
HTTP/2(现代浏览器)10050001:50http_v2_max_concurrent_streamsupstream并发能力HTTP/2 天然多路复用,一个 connection 可并行处理数十个 stream(即 request),connection 复用率最高
长轮询(SSE)100010100:1proxy_buffering offproxy_read_timeout每个 connection 长时间挂起,只处理极少量 request,connection 成为绝对瓶颈
gRPC over HTTP/220030001:15grpc_set_headerupstreamgrpc server 配置gRPC 依赖 HTTP/2 stream,但受 protobuf 序列化和业务逻辑影响,复用率低于纯 HTTP/2

这张表的价值在于,它帮你把抽象的“并发数”翻译成具体的系统资源压力。比如,你配置了worker_processes 4; worker_connections 2048,理论上最大 connection 数是4 * 2048 = 8192。如果业务是长轮询(SSE),那最多只能支撑 8192 个用户同时在线,再多就会出现accept() failed (24: Too many open files)错误;但如果业务是 HTTP/2,同样配置下,它能轻松支撑8192 * 50 ≈ 40 万 request/s的吞吐。所以,当你遇到“连接数打满”报警时,第一反应不应该是“扩容”,而是打开 access_log,用awk '{print $1}' | sort | uniq -c | sort -nr | head -20查看 top IP 的 connection 行为,再结合ss -s命令看total: 8192是否真的接近上限。很多时候,问题根源是某个客户端(比如一个 bug 的 SDK)在疯狂建连却不复用,或者 upstream 响应太慢导致 connection 长时间 hang 在ESTABLISHED状态。connection 是水池,request 是水流;水池大小固定,水流速度决定你能否持续供水。搞清这个比例,你就掌握了 Nginx 并发能力的底层密码。

3. 核心参数详解与实操配置:从原理到一行不落的落地

3.1 connection 相关参数:每一个数字都对应着一次系统调用

Nginx 的 connection 管理,几乎全部由events块下的参数控制。这些参数不是随便写的,每一个都直连操作系统内核,稍有不慎就会引发雪崩。下面我逐个拆解,附上我的生产环境实测值和调整逻辑:

  • worker_connections 4096;
    这是最常被问“设多大”的参数。它的含义是:每个 worker 进程最多能同时处理的 connection 数量。注意,是“同时处理”,不是“一生中处理过的总数”。计算公式很简单:最大并发连接数 = worker_processes × worker_connections。我线上环境通常设为4096,原因有三:第一,Linux 默认ulimit -n是 1024,必须先ulimit -n 65535并在/etc/security/limits.conf中永久设置;第二,4096是 2 的整数幂,epoll 内部哈希表扩容更友好;第三,超过8192后,单个 worker 的事件循环处理延迟会明显上升(我用ab -n 100000 -c 10000压测过,worker_connections 8192Requests per second反而比4096低 8%)。所以,与其盲目堆大数字,不如保证worker_processesworker_connections的乘积合理,并留出 20% 余量应对突发流量。

  • use epoll;
    这是 Linux 下的必选项。epollselect/poll的进化版,它用红黑树 + 就绪链表实现 O(1) 时间复杂度的事件通知,而select是 O(n)。在万级连接下,epoll的性能优势是数量级的。我见过有团队在 CentOS 6 上误用kqueue(FreeBSD 专用),结果压测时 CPU 100%,strace一看全是select()系统调用。记住:Linux 用epoll,FreeBSD/macOS 用kqueue,Windows 用iocp,别抄错。

  • multi_accept on;
    这个参数常被忽略,但它对高并发下的 connection 接收效率影响巨大。默认off时,一个 worker 在一次事件循环中,只接受一个新 connection;设为on后,它会一次性accept()所有等待队列里的新连接(即accept()直到EAGAIN)。实测表明,在 QPS 超过 5000 的场景下,multi_accept on能让 connection 接收延迟降低 30%。但要注意,它必须配合accept_mutex off(见下条)才能生效,否则会被互斥锁阻塞。

  • accept_mutex on;
    这是个“防惊群”的机制。当多个 worker 同时监听同一个端口时,内核会唤醒所有 worker 去accept(),但只有一个能成功,其余失败(EAGAIN),造成无谓的 CPU 浪费。accept_mutex on就是让 worker 们排队领号,一次只放一个去accept()。但在现代 Linux(2.6.20+)和epoll下,内核已优化了惊群问题,accept_mutex反而成了性能瓶颈。我的建议是:epoll环境下,一律设为off,并搭配multi_accept on。线上实测,accept_mutex off + multi_accept on组合比默认配置吞吐高 12%。

  • keepalive_timeout 65 20;
    这是 connection 复用的生命线。它有两个值:第一个65是客户端 connection 的空闲超时时间(秒),即如果 65 秒内没有新 request 到来,Nginx 就主动关闭这个 connection;第二个20是发送给客户端的Keep-Alive: timeout=20响应头,告诉客户端“你最多可以等我 20 秒,之后请主动关闭”。为什么两个值不同?因为 Nginx 自己的 timeout 可以设长一点,容错;但告诉客户端的 timeout 要设短一点,避免客户端傻等。我线上统一设为75 30,理由是:CDN 和中间代理(如 Cloudflare)通常会覆盖这个 header,设30能更快释放资源;而 Nginx 自身75秒的等待,足够覆盖绝大多数浏览器的默认 keep-alive 行为(Chrome 是 5 分钟,但实际受网络抖动影响,30~75 秒最稳妥)。

提示:keepalive_timeout不是越长越好。设成3600(1 小时),看似 connection 复用率高,实则会导致大量 connection 长时间 idle 占用 fd,一旦遭遇 slowloris 类攻击,瞬间打满连接池。安全与性能的平衡点,就在 60~90 秒之间。

3.2 request 相关参数:控制 HTTP 层行为的精细阀门

request 的参数分布在httpserverlocation多个层级,它们共同决定了 Nginx 如何解析、处理、响应每一次 HTTP 交互。以下是我在生产环境中反复打磨、验证有效的关键配置:

  • client_header_timeout 60;
    这个参数控制的是:从 connection 建立完成,到 Nginx 收到完整 HTTP 请求头(request headers)的最长等待时间。注意,它只管 header,不管 body。如果客户端在 60 秒内没发完Host:User-Agent:等 header,Nginx 就返回408 Request Timeout。我设为60是因为:正常 HTTP 请求,header 传输是毫秒级的;如果超过 60 秒,大概率是网络故障、客户端异常或恶意扫描。曾有一次,监控发现大量408tcpdump抓包一看,全是某 IDC 的出口防火墙在伪造 SYN 包探测,client_header_timeout就是第一道防线。

  • client_body_timeout 12;
    与上面对应,它控制的是:Nginx 收到请求头后,等待客户端发送请求体(request body,如 POST 数据)的超时时间。对于上传大文件的接口,这个值必须调大,否则用户上传到一半就断连。但普通 API,12秒足够——一个 10MB 文件在 10Mbps 带宽下,传输只需 8 秒,留 4 秒缓冲很充裕。关键是,它和client_max_body_size配合使用:client_max_body_size 100m;限制 body 大小,client_body_timeout 12限制传输时长,双保险防 DoS。

  • send_timeout 25;
    这个参数常被误解为“整个 response 的超时”,其实它是:Nginx 向客户端发送响应数据时,两次 write() 操作之间的最大间隔时间。比如,Nginx 正在把一个 1GB 的文件分片发送,如果某一片发送后,25 秒内客户端没确认接收(ACK),Nginx 就断开 connection。它针对的是“慢客户端”,不是“慢 upstream”。我设25是因为:TCP 的RTO(Retransmission Timeout)默认是 200ms~1s,send_timeout设为25秒,给了足够重传机会,又不至于让 connection 长期 hang 在CLOSE_WAIT状态。

  • reset_timedout_connection on;
    这是个“断尾求生”的利器。当 connection 因client_header_timeoutclient_body_timeoutsend_timeout超时而关闭时,如果设为on,Nginx 会向客户端发送一个 RST 包(复位),而不是 FIN 包(优雅关闭)。RST 能立即终止 TCP 连接,避免客户端还在傻等,也防止连接长时间停留在TIME_WAIT状态。线上高并发场景下,reset_timedout_connection on能显著降低TIME_WAIT连接数,实测减少 40%。但要注意:它只对超时关闭有效,正常流程不受影响。

  • lingering_time 30; lingering_timeout 5; lingering_close on;
    这三个参数是处理“半关闭连接”的终极方案。当客户端发送完 request 后,主动关闭了写端(FIN),但还开着读端,等着收 response。此时,如果 Nginx 的 response 很大,客户端可能已经断网,Nginx 还在傻等 ACK。lingering_close on启用延迟关闭;lingering_time 30表示最多等 30 秒;lingering_timeout 5表示每 5 秒检查一次,如果期间没收到新数据,就强制关闭。这套组合拳,能有效清理“僵尸连接”,特别适合 CDN 回源、移动端弱网场景。我线上所有location都加了这三行,netstat -an | grep :80 | grep TIME_WAIT | wc -l从平均 2000+ 降到 300 以内。

3.3 实操:一份经过千锤百炼的 events + http 块配置

光讲参数不够,给你一份我在线上稳定运行三年、支撑日均 20 亿请求的nginx.conf核心片段。这不是模板,而是每一行都带着血泪教训:

# --- events 块:connection 的心脏 --- events { use epoll; # Linux 必选,别犹豫 worker_connections 4096; # 每 worker 4096 连接,够用且高效 multi_accept on; # 一次 accept 所有等待连接 accept_mutex off; # epoll 下关闭互斥锁,提升吞吐 # 注意:这里不写 worker_cpu_affinity,它由 systemd 服务文件管理 } # --- http 块:request 的大脑 --- http { include mime.types; default_type application/octet-stream; # --- 日志格式:必须包含 connection 和 request 的关键指标 --- log_format main '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$request_time $upstream_response_time $pipe $upstream_cache_status ' '$connection $connection_requests'; # 关键!$connection 是当前 connection ID,$connection_requests 是该 connection 上已处理的 request 数 # --- 性能与安全基线 --- sendfile on; # 内核零拷贝,必须开 tcp_nopush on; # 配合 sendfile,攒够 TCP 包再发 tcp_nodelay on; # 禁用 Nagle 算法,小包立即发(对 API 延迟敏感) keepalive_timeout 75 30; # connection 复用:自己等 75 秒,告诉客户端等 30 秒 types_hash_max_size 2048; # --- request 超时控制:精准打击各类异常 --- client_header_timeout 60; # header 60 秒没来完?408 client_body_timeout 12; # body 12 秒没传完?408 send_timeout 25; # 发送响应,两次 write 间隔超 25 秒?断开 reset_timedout_connection on; # 超时就 RST,不拖泥带水 # --- 防御慢连接和慢客户端 --- lingering_close on; # 启用延迟关闭 lingering_time 30; # 最多 linger 30 秒 lingering_timeout 5; # 每 5 秒检查一次 # --- 连接数限制:保护自己,也保护 upstream --- limit_conn_zone $binary_remote_addr zone=addr:10m; # 按 IP 限连接 limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s; # 按 IP 限速 # --- server 块示例:体现 connection/request 的协同 --- server { listen 80; server_name example.com; # 这里是 connection 的入口,也是 request 的起点 location /api/ { # 限流:每个 IP 每秒最多 10 个 request,burst=20 允许突发 limit_req zone=one burst=20 nodelay; # 限连接:每个 IP 最多 100 个 connection,防连接耗尽 limit_conn addr 100; # proxy_pass:request 转发,但 connection 复用由 upstream 决定 proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Connection ''; # 清空 Connection header,让 upstream 也能复用 # 超时:这三个 timeout 控制的是与 upstream 的 connection 行为 proxy_connect_timeout 5; # 建连 upstream 超时 proxy_send_timeout 30; # 发送 request 给 upstream 超时 proxy_read_timeout 60; # 等 upstream response 超时 } } }

这份配置的精髓在于:所有参数都服务于一个目标——让 connection 尽可能长地活着,让 request 尽可能快地流转multi_accept onaccept_mutex off让 connection 进来得更快;keepalive_timeout 75 30proxy_http_version 1.1让 connection 出去得更久;limit_reqlimit_conn则像交通警察,在入口处就分流,避免劣质 request 污染优质 connection。它不是最优的,但它是经过真实流量淬炼、能扛住各种脏流量冲击的“稳态配置”。

4. 排查实战:connection 和 request 异常的 7 个现场诊断案例

4.1 案例一:accept() failed (24: Too many open files)—— connection 资源耗尽

现象:Nginx error.log 突然刷屏accept() failed (24: Too many open files)ps aux | grep nginx显示 worker 进程 CPU 100%,但netstat -an | grep :80 | wc -l显示连接数只有 2000,远低于worker_connections设置。
排查思路Too many open files是系统级错误,说明进程打开的文件描述符(fd)达到上限。但netstat显示的连接数 ≠ fd 数,因为 fd 还包括日志文件、临时文件、upstream 连接等。
诊断步骤

  1. 查看当前 worker 进程的 fd 使用量:ls -l /proc/$(pgrep nginx | head -1)/fd/ | wc -l。如果接近ulimit -n,就坐实了。
  2. 查看哪些 fd 占得多:lsof -p $(pgrep nginx | head -1) | awk '{print $9}' | sort | uniq -c | sort -nr | head -10。我遇到过最多的是socket:[123456789](connection)和/var/log/nginx/access.log(日志轮转未 reload)。
  3. 根本原因:ulimit -n设置太低,或日志轮转后未kill -USR1通知 Nginx 重新打开日志文件,导致旧 fd 一直占用。
    解决方案
  • 永久提升ulimit:在/etc/security/limits.confnginx soft nofile 65535nginx hard nofile 65535
  • 日志轮转脚本末尾加kill -USR1 $(cat /var/run/nginx.pid)
  • nginx.confevents块加worker_rlimit_nofile 65535;,让 Nginx 主动申请。

实操心得:不要迷信netstat的连接数。ss -s才是权威,它会告诉你Total: 8192 (kernel 8192),这才是真实的 connection 池上限。netstat只统计 ESTABLISHED,而ss -s统计所有状态。

4.2 案例二:upstream timed out (110: Connection timed out)—— request 卡在 upstream

现象:access.log 里大量504 Gateway Timeout$upstream_response_time字段为空或为-$request_time却高达 60 秒。
排查思路504是 Nginx 自己返回的,说明它等 upstream 响应超时了。$upstream_response_time为空,证明 upstream 根本没返回任何数据,connection 卡在了SYN_SENTESTABLISHED等待状态。
诊断步骤

  1. 检查proxy_read_timeout设置。如果设为60,而 upstream 真实响应是 65 秒,必然 504。
  2. tcpdump抓包:tcpdump -i any port 8080 -w upstream.pcap(假设 upstream 是 8080),然后wireshark打开,看 Nginx 的 SYN 包发出去后,有没有收到 upstream 的 SYN-ACK。如果没有,说明网络不通或 upstream 服务没起来;如果有,但没收到 HTTP 响应,说明 upstream 业务逻辑卡死。
  3. 检查 upstream 服务器的netstat -an | grep :8080 | grep ESTABLISHED | wc -l,如果远超其max_connections,就是 upstream 连接池被打满了。
    解决方案
  • 调大proxy_read_timeout,但治标不治本;
  • 在 upstream 块加max_fails=3 fail_timeout=30s,让 Nginx 自动踢掉不可用节点;
  • 最根本:优化 upstream 代码,加超时、加熔断、加监控。

实操心得:proxy_read_timeout不是越长越好。设成300(5 分钟),等于把 Nginx 变成一个“连接黑洞”,上游一卡,所有 connection 都 hang 住,最终拖垮整个 Nginx。合理的做法是:proxy_read_timeout设为 upstream P99 延迟的 2 倍,比如 P99 是 800ms,就设2秒。

4.3 案例三:client intended to send too large body—— request body 超限

现象:POST 请求返回413 Request Entity Too Large,但client_max_body_size已设为100m
排查思路413是 Nginx 在client_body_timeout阶段返回的,但触发条件有两个:一是 body 大小超client_max_body_size,二是 body 传输时间超client_body_timeout。前者是硬限制,后者是软限制。
诊断步骤

  1. 确认请求的Content-Length头。如果Content-Length: 104857600(100MB),而client_max_body_size 100m,理论上应该通过。但如果客户端是分块传输(chunked encoding),Nginx 会先收 header,再收 body,此时client_body_timeout开始计时。
  2. curl -v -X POST --data-binary @largefile.zip http://example.com/upload模拟,看是卡在Uploading阶段(timeout),还是直接返回413(size 超限)。
    解决方案
  • 如果是 size 问题:在httpserverlocation块里加client_max_body_size 200m;
  • 如果是 timeout 问题:加client_body_timeout 300;(5 分钟);
  • 更优解:对上传接口单独配置,location /upload/ { client_max_body_size 500m; client_body_timeout 600; }

实操心得:永远不要在http块全局设client_max_body_size 0(禁用限制)。这等于给 DoS 攻击开了绿灯。应该按需在location级别精细化控制。

4.4 案例四:upstream prematurely closed connection—— connection 被 upstream 主动关闭

现象:access.log 里 `502 Bad Gateway

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询