如何通过 Nginx 的 $pipe 变量追踪客户端请求流水线化过程?
- 内容介绍
- 文章标签
- 相关推荐
本文共计900个文字,预计阅读时间需要4分钟。
$pipe 是 Nginx 内置的只读变量,用于标识当前请求是否通过 HTTP 流水线(HTTP pipelining)方式发送。该变量用于标记当前请求是否是通过 HTTP 流水线(HTTP pipelining)方式发送的——即客户端是否在同一 TCP 连接中连续发送多个请求而不等待前一个请求的响应。
该变量的值可以是:
确认 $pipe 变量可用性与基础行为
Nginx 1.1.4+ 原生支持 $pipe,无需额外模块。它仅在请求处理阶段有效(如 log_format、if 判断、map 指令中),不可用于 rewrite 或 proxy_set_header 等指令中修改请求头。其取值严格由 Nginx 在解析请求行时判定:
- 若请求是连接中第二个及以上、且前序请求尚未响应完毕,则 $pipe = "p"
- 若为连接首请求,或连接启用 keepalive 但无流水线行为,则 $pipe = "."
- 该变量与 $connection、$request_length 等协同可辅助识别异常连接模式
在日志中记录并分析流水线请求
将 $pipe 加入 access_log 格式,是监控流水线行为最直接的方式:
log_format pipeline_log '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" $pipe $connection'; access_log /var/log/nginx/pipeline.log pipeline_log;
随后可通过日志分析工具(如 awk、goaccess 或 ELK)统计 p 出现频次、关联 IP、请求路径分布等。例如快速查看所有流水线请求:
awk '$12 == "p" {print}' /var/log/nginx/pipeline.log
结合 map 实现条件响应或限流
利用 map 指令将 $pipe 映射为布尔标记,可用于精细化控制:
map $pipe $is_pipelined { default 0; p 1; } <p>server { location /api/ {</p><h1>拒绝流水线请求(适用于需强顺序保障的接口)</h1><pre class="brush:php;toolbar:false;"> if ($is_pipelined) { return 403 "Pipelining not allowed"; } proxy_pass https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e; }
}
⚠️ 注意:if 在 location 中有局限,更健壮的做法是用 limit_req 配合自定义 key:
limit_req_zone $binary_remote_addr$pipe zone=pipetest:10m rate=10r/s; <p>location / { limit_req zone=pipetest burst=5 nodelay; proxy_pass <a href="https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e">https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e</a>; }
这样可对同一 IP 的流水线请求($pipe="p")和普通请求($pipe=".")区分限流。
调试与验证流水线行为
因主流浏览器不发起流水线请求,需用 curl 或专用工具构造测试:
- 使用
curl --http1.1并配合printf手动拼接请求(注意换行与空行) - 用
nc或openssl s_client直连 Nginx 端口发送原始 HTTP 请求 - 观察 access_log 中对应行的 $pipe 字段是否为
p,同时检查 $connection 是否复用(同一连接 ID 多次出现) - 确认 Nginx 配置中
keepalive_timeout> 0 且未设置disable_symlinks等干扰解析的指令
若始终无法触发 $pipe="p",需排查客户端是否真正发送了未等待响应的连续请求,以及 Nginx 是否启用了 HTTP/1.1 支持(默认开启)。
本文共计900个文字,预计阅读时间需要4分钟。
$pipe 是 Nginx 内置的只读变量,用于标识当前请求是否通过 HTTP 流水线(HTTP pipelining)方式发送。该变量用于标记当前请求是否是通过 HTTP 流水线(HTTP pipelining)方式发送的——即客户端是否在同一 TCP 连接中连续发送多个请求而不等待前一个请求的响应。
该变量的值可以是:
确认 $pipe 变量可用性与基础行为
Nginx 1.1.4+ 原生支持 $pipe,无需额外模块。它仅在请求处理阶段有效(如 log_format、if 判断、map 指令中),不可用于 rewrite 或 proxy_set_header 等指令中修改请求头。其取值严格由 Nginx 在解析请求行时判定:
- 若请求是连接中第二个及以上、且前序请求尚未响应完毕,则 $pipe = "p"
- 若为连接首请求,或连接启用 keepalive 但无流水线行为,则 $pipe = "."
- 该变量与 $connection、$request_length 等协同可辅助识别异常连接模式
在日志中记录并分析流水线请求
将 $pipe 加入 access_log 格式,是监控流水线行为最直接的方式:
log_format pipeline_log '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" $pipe $connection'; access_log /var/log/nginx/pipeline.log pipeline_log;
随后可通过日志分析工具(如 awk、goaccess 或 ELK)统计 p 出现频次、关联 IP、请求路径分布等。例如快速查看所有流水线请求:
awk '$12 == "p" {print}' /var/log/nginx/pipeline.log
结合 map 实现条件响应或限流
利用 map 指令将 $pipe 映射为布尔标记,可用于精细化控制:
map $pipe $is_pipelined { default 0; p 1; } <p>server { location /api/ {</p><h1>拒绝流水线请求(适用于需强顺序保障的接口)</h1><pre class="brush:php;toolbar:false;"> if ($is_pipelined) { return 403 "Pipelining not allowed"; } proxy_pass https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e; }
}
⚠️ 注意:if 在 location 中有局限,更健壮的做法是用 limit_req 配合自定义 key:
limit_req_zone $binary_remote_addr$pipe zone=pipetest:10m rate=10r/s; <p>location / { limit_req zone=pipetest burst=5 nodelay; proxy_pass <a href="https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e">https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e</a>; }
这样可对同一 IP 的流水线请求($pipe="p")和普通请求($pipe=".")区分限流。
调试与验证流水线行为
因主流浏览器不发起流水线请求,需用 curl 或专用工具构造测试:
- 使用
curl --http1.1并配合printf手动拼接请求(注意换行与空行) - 用
nc或openssl s_client直连 Nginx 端口发送原始 HTTP 请求 - 观察 access_log 中对应行的 $pipe 字段是否为
p,同时检查 $connection 是否复用(同一连接 ID 多次出现) - 确认 Nginx 配置中
keepalive_timeout> 0 且未设置disable_symlinks等干扰解析的指令
若始终无法触发 $pipe="p",需排查客户端是否真正发送了未等待响应的连续请求,以及 Nginx 是否启用了 HTTP/1.1 支持(默认开启)。

