在 Apache 的日常运维中,请求体读取超时是一个容易被忽视但又非常关键的配置项。默认情况下 Apache 对接收客户端数据的等待时间有上限,一旦客户端发送 POST 数据的速度太慢,或者上传过程中网络抖动,连接就可能被服务端直接掐断,客户端看到的是 408 错误或者连接重置。反过来,如果这个超时设得太大,又容易给慢速攻击(Slowloris 一类)留下可乘之机。本文就来把 Apache 中与请求体读取相关的超时配置彻底讲清楚。

一、Timeout 指令:全局的基础超时
Apache 核心提供了一个 Timeout 指令,它定义了 Apache 等待三类 I/O 事件的最长时间:等待客户端发送请求的时间、等待客户端返回响应确认的时间(长连接中等待下一次请求的时间由 KeepAliveTimeout 单独控制),以及等待后端 CGI 或反向代理后端返回数据的时间。默认值通常是 60 秒,具体取决于发行版。
这个值是全局兜底性质的。当客户端通过 POST 上传一个大文件,中途网络卡顿导致数据流中断超过 Timeout 秒,Apache 就会主动断开连接。所以如果你的业务里有移动端弱网上传、跨境传输等场景,单纯调大 Timeout 是最直接的办法:
# 在 httpd.conf 或 apache2.conf 中 Timeout 300
但要注意,调大 Timeout 是一把双刃剑。它同时影响 CGI 脚本的最长执行等待时间、代理后端的响应等待时间,如果脚本里有长时间任务,原本靠 60 秒兜底释放连接的机制会失效,服务器上堆积的半开连接会明显增多,占用 worker 进程或线程。对于 prefork 模式下的 Apache,每个连接都占一个进程,这种堆积的代价尤其高。因此更推荐的做法,是使用专门的 mod_reqtimeout 模块来精细控制请求接收阶段,而不是粗暴地改全局 Timeout。
二、mod_reqtimeout:精细化控制请求接收
mod_reqtimeout 是 Apache 2.2.15 之后引入的模块(Apache 2.4 默认编译包含),它的设计初衷就是为了防御 Slowloris 慢速攻击,同时给正常的慢速上传留出合理的缓冲空间。它通过 RequestReadTimeout 指令,把接收一个请求拆分成两个阶段来分别限制:header 阶段(从连接建立到请求头读完)和 body 阶段(接收 POST 数据的阶段)。
RequestReadTimeout 的基本语法是 RequestReadTimeout header=时间[[-最大时间],minrate=速率] body=时间[[-最大时间],minrate=速率]。其中第一段固定时间是初始超时,也就是不管数据传得多慢,只要开始有数据进来,计时就会被刷新;minrate 表示数据速率下限,每收到 minrate 字节的数据,超时时间就延长一秒,这样只要客户端持续有数据发送,连接就不会被掐断;可选的最大时间则给整个阶段设定一个硬上限。典型配置如下:
# 启用模块(Debian/Ubuntu)
# a2enmod reqtimeout
# httpd.conf 或 conf-available/reqtimeout.conf
<IfModule reqtimeout_module>
# 请求头阶段:初始 20 秒,之后每收到 500 字节延长 1 秒,最长 40 秒
RequestReadTimeout header=20-40,minrate=500
# 请求体阶段:初始 20 秒,之后每收到 500 字节延长 1 秒,不设上限
RequestReadTimeout body=20,minrate=500
</IfModule>这个配置的含义需要仔细理解。header 部分的 20-40 表示:起始超时 20 秒,收到请求头数据后每 500 字节增加 1 秒,但无论如何不超过 40 秒。正常浏览器发送请求头只要几百字节,20 秒初始值绰绰有余;而 Slowloris 攻击每几秒滴几字节来维持连接,就算它一直发,也会被 40 秒的硬上限拦住。body 部分没有设置最大时间,意味着只要客户端保持每秒至少 500 字节的传输速率,一个 100MB 的文件上传理论上可以持续很久都不会超时,这就同时兼顾了安全性和大文件上传的可用性。
值得一提的是,Debian、Ubuntu 这类发行版的默认配置文件里,mod_reqtimeout 的默认值是 header=20-40,minrate=500 body=20,minrate=500,对大多数网站是合适的。但如果你遇到了 408 错误,先别急着禁用模块,而是应该分析 body 阶段的 minrate 是否对客户端太苛刻。比如上传者实际速率只有 200 字节每秒,那确实会被判定超时,可以考虑把 body 的 minrate 降到 100,或者把初始时间提高到 30 秒。
三、典型场景的配置方案与排查思路
不同业务形态对超时的需求差异很大,下面看几个典型场景。第一个是图片、视频等大文件上传站,客户端可能是移动端弱网环境,这种情况建议 body 初始时间给足,minrate 放低,同时用最大时间防止极端情况,例如 body=30-600,minrate=100,既允许非常慢的上传,又保证单个请求体接收最长不超过 600 秒。
# 大文件上传站点 RequestReadTimeout header=20-40,minrate=500 RequestReadTimeout body=30-600,minrate=100
第二个场景是 Apache 作为反向代理(配合 mod_proxy),前面挂 Nginx 或后面接 Tomcat。要注意 mod_reqtimeout 只作用于 Apache 与直接客户端之间的连接,如果客户端经过 CDN 或者前置 Nginx 再到 Apache,那么 Apache 看到的发送方是前置服务器,速率通常很快,超时问题可能出在前置层,排查时不要只盯 Apache 一处。同时 Timeout 指令还会影响 ProxyTimeout 未设置时代理后端的等待行为,多层超时要理清楚哪一层先超时,逐层核对日志。
第三个场景是纯安全加固,目标是把慢速攻击窗口压到最小。如果业务里根本没有大 POST 请求,可以把 body 的初始超时压缩到 10 秒甚至更低,并设置一个较小的时间上限。还可以配合 KeepAliveTimeout、MaxRequestWorkers、mod_limitipcon 等一起使用,构成多层防线。配置修改后记得用 apachectl configtest 检查语法,再平滑重载:
# 检查语法 apachectl configtest # 平滑重载配置 apachectl graceful
排查超时问题时,日志是最重要的依据。打开 LogLevel 到 info 或 debug,mod_reqtimeout 在主动断开连接时会记录原因,比如提示请求头接收超时或请求体数据速率过低,看到这类记录就能确认是超时配置而不是后端应用的问题。再用 curl --limit-rate 模拟慢速上传,可以很方便地验证新配置是否符合预期:
# 以 100 字节每秒的速率发送一个 1MB 的文件做测试 curl -v --limit-rate 100 -F "file=@test.bin" http://www.example-ipipp.com/upload/
总的来说,Apache 请求体读取超时的管理思路是:全局 Timeout 保持一个相对保守的值,把请求接收阶段的精细控制交给 mod_reqtimeout,通过 header、body 两阶段加上 minrate 机制,在防御慢速攻击和容忍慢速上传之间找到平衡点。遇到 408 或连接被重置时,先看日志确认断开原因,再结合业务的上传特征调整初始超时和 minrate,最后别忘了逐层检查代理链路上其他组件的超时设置,这样才能彻底解决问题。
Apache 超时设置mod_reqtimeout请求体读取修改时间:2026-09-04 01:30:59