ngx_http_terminate_request

ngx_http_terminate_request 1 定义night_http_terminate_request 函数 定义在 ./nginx-1.24.0/src/http/ngx_http_request.cstaticvoidngx_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;mrr-main;ngx_log_debug1(NGX_LOG_DEBUG_HTTP,r-connection-log,0,http terminate request count:%d,mr-count);if(rc0(mr-headers_out.status0||mr-connection-sent0)){mr-headers_out.statusrc;}clnmr-cleanup;mr-cleanupNULL;while(cln){if(cln-handler){cln-handler(cln-data);}clncln-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-error1;r-write_event_handlerngx_http_request_finalizer;return;}engx_http_ephemeral(mr);mr-posted_requestsNULL;mr-write_event_handlerngx_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;mrr-main;ngx_log_debug1(NGX_LOG_DEBUG_HTTP,r-connection-log,0,http terminate request count:%d,mr-count);2 设置 HTTP 状态码if(rc0(mr-headers_out.status0||mr-connection-sent0)){mr-headers_out.statusrc;}设置 HTTP 状态码 判断条件rc 0是有效的 HTTP 状态码 并且主请求的响应状态尚未设置mr-headers_out.status 0 或者连接上还没有发送过任何字节mr-connection-sent 0。 若条件成立将主请求的 headers_out.status 设为 rc。 意义只有在“还有机会告知客户端失败原因”的前提下才写入状态码。 如果响应头已经发送强行修改状态码会导致协议错误 如果已经有数据发送则通常状态码已定。 因此这里做了一次“尽力而为”的尝试 确保错误状态能尽可能传回客户端但不破坏已建立的响应流。3 清理回调clnmr-cleanup;mr-cleanupNULL;while(cln){if(cln-handler){cln-handler(cln-data);}clncln-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-error1;r-write_event_handlerngx_http_request_finalizer;return;}engx_http_ephemeral(mr);mr-posted_requestsNULL;mr-write_event_handlerngx_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) 该函数会减少主请求的引用计数、释放连接资源、回收内存池等完成请求的最终销毁