news 2026/5/27 13:58:18

ngx_http_terminate_request

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ngx_http_terminate_request

1 定义

night_http_terminate_request 函数 定义在 ./nginx-1.24.0/src/http/ngx_http_request.c
staticvoidngx_http_terminate_request(ngx_http_request_t*r,ngx_int_trc){ngx_http_cleanup_t*cln;ngx_http_request_t*mr;ngx_http_ephemeral_t*e;mr=r->main;ngx_log_debug1(NGX_LOG_DEBUG_HTTP,r->connection->log,0,"http terminate request count:%d",mr->count);if(rc>0&&(mr->headers_out.status==0||mr->connection->sent==0)){mr->headers_out.status=rc;}cln=mr->cleanup;mr->cleanup=NULL;while(cln){if(cln->handler){cln->handler(cln->data);}cln=cln->next;}ngx_log_debug2(NGX_LOG_DEBUG_HTTP,r->connection->log,0,"http terminate cleanup count:%d blk:%d",mr->count,mr->blocked);if(mr->write_event_handler){if(mr->blocked){r->connection->error=1;r->write_event_handler=ngx_http_request_finalizer;return;}e=ngx_http_ephemeral(mr);mr->posted_requests=NULL;mr->write_event_handler=ngx_http_terminate_handler;(void)ngx_http_post_request(mr,&e->terminal_posted_request);return;}ngx_http_close_request(mr,rc);}
ngx_http_terminate_request 函数 是 nginx 中用于安全终止 HTTP 请求的核心函数。

2 详解

1 函数签名

staticvoidngx_http_terminate_request(ngx_http_request_t*r,ngx_int_trc)
返回值 返回类型 `void` 函数不向调用者返回任何值。 该函数是一次副作用操作,它不负责计算或返回成功/失败指示, 而是直接修改请求的状态、执行清理、并将最终关闭动作插入事件循环或立即执行。 请求终止的结果通过修改请求对象本身及事件驱动机制来体现,无需通过返回值传递。
第一个参数 `ngx_http_request_t *r` 指向 `ngx_http_request_t` 结构体的指针。 该结构体是 nginx 中表示一个 HTTP 请求的核心对象 该参数是输入,是本函数要 终止的HTTP 请求
第二个参数 `ngx_int_t rc` 此次终止的原因码

2 逻辑流程

1 局部变量 2 设置 HTTP 状态码 3 清理回调 4 延迟终结 5 关闭请求

1 局部变量
{ngx_http_cleanup_t*cln;ngx_http_request_t*mr;ngx_http_ephemeral_t*e;mr=r->main;ngx_log_debug1(NGX_LOG_DEBUG_HTTP,r->connection->log,0,"http terminate request count:%d",mr->count);

2 设置 HTTP 状态码
if(rc>0&&(mr->headers_out.status==0||mr->connection->sent==0)){mr->headers_out.status=rc;}
设置 HTTP 状态码: 判断条件:rc > 0(是有效的 HTTP 状态码), 并且主请求的响应状态尚未设置(mr->headers_out.status == 0) 或者连接上还没有发送过任何字节(mr->connection->sent == 0)。 若条件成立,将主请求的 headers_out.status 设为 rc。 意义:只有在“还有机会告知客户端失败原因”的前提下才写入状态码。 如果响应头已经发送,强行修改状态码会导致协议错误; 如果已经有数据发送,则通常状态码已定。 因此这里做了一次“尽力而为”的尝试, 确保错误状态能尽可能传回客户端,但不破坏已建立的响应流。

3 清理回调
cln=mr->cleanup;mr->cleanup=NULL;while(cln){if(cln->handler){cln->handler(cln->data);}cln=cln->next;}ngx_log_debug2(NGX_LOG_DEBUG_HTTP,r->connection->log,0,"http terminate cleanup count:%d blk:%d",mr->count,mr->blocked);
#1 取出并清除清理链表: mr->cleanup 指向主请求关联的清理回调链表头。 将其拷贝到局部变量 cln 后立即置空 mr->cleanup。 目的:防止在后续执行清理回调的过程中, 某些逻辑再次试图添加新的清理项或触发二次清理,
#2 执行所有清理回调: 遍历从主请求获取的清理链表。 对每一个节点,若其 handler 不为空,则调用 handler(cln->data)。 这些回调通常由模块注册, 用于释放与该请求关联的各种资源:关闭文件描述符、删除临时文件、 归还内存池中的大块内存、释放外部连接等。 遍历完全部节点,意味着该请求占用的所有外部资源已被释放, 只剩请求结构体本身和连接尚待处理。

4 延迟终结
if(mr->write_event_handler){if(mr->blocked){r->connection->error=1;r->write_event_handler=ngx_http_request_finalizer;return;}e=ngx_http_ephemeral(mr);mr->posted_requests=NULL;mr->write_event_handler=ngx_http_terminate_handler;(void)ngx_http_post_request(mr,&e->terminal_posted_request);return;}
#1 判断主请求是否仍在参与写事件: write_event_handler 是请求的一个函数指针, 当请求需要向客户端发送数据时, 该指针被设置为相应的处理函数。 若请求已进入最终完成状态或从未开始发送响应,该指针可能为空。 如果指针非空,说明请求还“活”在 nginx 的事件循环中,正在或等待执行写操作。 此时不能直接销毁请求对象,必须通过事件机制安排其关闭,否则可能引发悬空指针或事件混乱。
#2 阻塞状态下的特殊处理: 如果主请求被标记为 blocked(例如正在等待子请求或持有内部锁), 强行将其投入终端队列可能会破坏同步逻辑或导致死锁。 此时采取更保守的策略: 将当前请求所在连接标记为出错(r->connection->error = 1), 这会使后续事件处理检测到错误并尽快结束连接。 将当前请求 r 的写事件处理器替换为 ngx_http_request_finalizer。 该终结器函数会在下一次写事件被触发时执行,最终安全销毁请求。 直接返回,不再进行后续的投递或关闭操作。 这样保证了在复杂异步场景下,请求的销毁被推迟到解除阻塞之后的安全点, 且通过错误标记避免了死等。
#3 当主请求有写事件处理器且未被阻塞时, 执行以下操作: e = ngx_http_ephemeral(mr); 获取主请求的临时数据(ephemeral 结构), mr->posted_requests = NULL; mr->posted_requests 一个挂在主请求(mr)上的 “待处理任务”链表。 请求要终止,这些任务已经毫无意义,清空 mr->write_event_handler = ngx_http_terminate_handler; 将主请求的写事件处理器替换为 ngx_http_terminate_handler。 ngx_http_terminate_handler 是一个特定回调, 它的职责就是在被事件循环调用时执行最终的关闭操作 这样就把“请求最终销毁”的动作封装成了一个可通过事件触发的任务。 把 write_event_handler 更新为 ngx_http_terminate_handler, 下一次写事件被触发时,执行 ngx_http_terminate_handler 函数,终结请求 (void) ngx_http_post_request(mr, &e->terminal_posted_request); 将主请求通过 terminal_posted_request 节点挂接到 nginx 的全局终端事件队列中。 当当前正在处理的事件结束后,nginx 的事件循环会检查并处理 posted 请求队列, 此时会调用刚才设置的 ngx_http_terminate_handler,从而在安全的环境中完成请求销毁。 return; 函数立即返回
逻辑总结 1 获取临时数据:取得预分配的 `terminal_posted_request` 节点,为内部队列挂载做准备。 2 清空待处理任务:丢弃所有尚未执行的子请求或其他延迟任务,终结时不再需要它们。 3 改变行为定义:将 `write_event_handler` 设置为 `ngx_http_terminate_handler`, 这意味着“将来当这个请求被调度执行时,执行的是终结销毁动作”。 4 投递到内部队列:通过 `ngx_http_post_request` 将请求挂入事件循环的终端 posted 队列, 从而强制事件循环在本次迭代的末尾无条件地调用刚才设置的终结 handler。

5 关闭请求
ngx_http_close_request(mr,rc);}
如果主请求的 write_event_handler 为空, 说明请求已经不在任何写事件流程中(可能从未开始发送响应,或已完整结束), 此时可以安全地立即销毁。 调用 ngx_http_close_request(mr, rc), 该函数会减少主请求的引用计数、释放连接资源、回收内存池等,完成请求的最终销毁
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/27 13:48:02

新手入门教程使用curl命令快速测试Taotoken大模型API

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 新手入门教程使用curl命令快速测试Taotoken大模型API 对于刚接触大模型API的开发者而言,使用curl命令进行快速测试是一…

作者头像 李华
网站建设 2026/5/27 13:47:01

一份 Agent 工程岗 JD,暴露了市场真正想要什么样的人

背景最近刷到一份 Agent 工程师的岗位 JD,跟以前的前端岗位完全不一样了。我心想:这大概就是现在以及接下来几年的方向了。 JD 里写的东西包括: TypeScript 做 Agent 轨迹可视化Python / Rust 对接 RL 训练框架Docker / Kubernetes 管理 Agen…

作者头像 李华
网站建设 2026/5/27 13:45:29

矩阵结构驱动的内点法:为四旋翼无人机实时轨迹规划提速10倍

1. 项目概述四旋翼无人机要在复杂环境中实现自主飞行,核心挑战之一就是“实时轨迹规划”。这可不是简单地画一条从A点到B点的线,而是要在毫秒级的时间内,算出一条既能让无人机飞得稳、飞得快,又能完美避开所有障碍物的“聪明”路径…

作者头像 李华
网站建设 2026/5/27 13:45:29

程序员狂喜!UU远程终端功能直接把远程运维效率拉满[特殊字符]✨

家人们谁懂啊!!作为天天和代码、服务器打交道的程序猿/运维,远程调试环境、部署项目真的太折磨人了😭 之前为了跑个命令,要么得用又卡又难用的第三方SSH工具,要么就得守在工位电脑前,连出门喝杯…

作者头像 李华
网站建设 2026/5/27 13:44:31

基于色度振动与AR标记阵列的近屏隐形交互技术实现

1. 项目概述与核心思路如果你曾经在商场里对着一个巨大的数字地图,想用手机“点”一下某个店铺来获取优惠券,却发现要么得扫一个碍眼的二维码,要么得手动输入一串复杂的代码,那你大概能体会到传统屏幕交互的尴尬。这正是我们这群搞…

作者头像 李华