当前位置: 首页 > news >正文

ngx_http_core_find_config_phase

1 定义

ngx_http_core_find_config_phase 函数 定义在 src/http/ngx_http_core_module.c
ngx_int_tngx_http_core_find_config_phase(ngx_http_request_t*r,ngx_http_phase_handler_t*ph){u_char*p;size_tlen;ngx_int_trc;ngx_http_core_loc_conf_t*clcf;r->content_handler=NULL;r->uri_changed=0;rc=ngx_http_core_find_location(r);if(rc==NGX_ERROR){ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);returnNGX_OK;}clcf=ngx_http_get_module_loc_conf(r,ngx_http_core_module);if(!r->internal&&clcf->internal){ngx_http_finalize_request(r,NGX_HTTP_NOT_FOUND);returnNGX_OK;}ngx_log_debug2(NGX_LOG_DEBUG_HTTP,r->connection->log,0,"using configuration \"%s%V\"",(clcf->noname?"*":(clcf->exact_match?"=":"")),&clcf->name);ngx_http_update_location_config(r);ngx_log_debug2(NGX_LOG_DEBUG_HTTP,r->connection->log,0,"http cl:%O max:%O",r->headers_in.content_length_n,clcf->client_max_body_size);if(r->headers_in.content_length_n!=-1&&!r->discard_body&&clcf->client_max_body_size&&clcf->client_max_body_size<r->headers_in.content_length_n){ngx_log_error(NGX_LOG_ERR,r->connection->log,0,"client intended to send too large body: %O bytes",r->headers_in.content_length_n);r->expect_tested=1;(void)ngx_http_discard_request_body(r);ngx_http_finalize_request(r,NGX_HTTP_REQUEST_ENTITY_TOO_LARGE);returnNGX_OK;}if(rc==NGX_DONE){ngx_http_clear_location(r);r->headers_out.location=ngx_list_push(&r->headers_out.headers);if(r->headers_out.location==NULL){ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);returnNGX_OK;}r->headers_out.location->hash=1;r->headers_out.location->next=NULL;ngx_str_set(&r->headers_out.location->key,"Location");if(r->args.len==0){r->headers_out.location->value=clcf->escaped_name;}else{len=clcf->escaped_name.len+1+r->args.len;p=ngx_pnalloc(r->pool,len);if(p==NULL){ngx_http_clear_location(r);ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);returnNGX_OK;}r->headers_out.location->value.len=len;r->headers_out.location->value.data=p;p=ngx_cpymem(p,clcf->escaped_name.data,clcf->escaped_name.len);*p++='?';ngx_memcpy(p,r->args.data,r->args.len);}ngx_http_finalize_request(r,NGX_HTTP_MOVED_PERMANENTLY);returnNGX_OK;}r->phase_handler++;returnNGX_AGAIN;}
ngx_http_core_find_config_phase 函数 是 `NGX_HTTP_FIND_CONFIG_PHASE` 阶段的检查器, 主要负责为请求执行 location 匹配并应用相应的配置。 同时,它还会处理内部访问限制(`internal`)、拒绝过大的请求体, 以及在需要时生成目录重定向(301),最终将请求推进到下一个处理阶段。

2 详解

1 函数签名

ngx_int_tngx_http_core_find_config_phase(ngx_http_request_t*r,ngx_http_phase_handler_t*ph)
返回值 返回函数执行结果的状态码, 告知调用者执行情况
参数1 ngx_http_request_t *r 指向当前 HTTP 请求上下文结构体
参数2 ngx_http_phase_handler_t *ph 当前阶段处理引擎数组条目的指针 指向 ngx_http_phase_handler_t 结构体的指针。 该结构体包含 checker、handler、next 三个字段, 代表阶段引擎数组中的一个元素

2 逻辑流程

1 局部变量 2 执行 location 匹配 3 匹配出错 4 获取匹配到的 location 的核心配置 5 检查 internal 访问限制 6 应用 location 配置到请求 7 判断请求体是否过大 8 需要外部重定向 9 正常出口

1 局部变量
{u_char*p;size_tlen;ngx_int_trc;ngx_http_core_loc_conf_t*clcf;

r->content_handler=NULL;r->uri_changed=0;
将请求的内容处理器指针清空,并将 URI 是否被重写过的标记置零。 进入 FIND_CONFIG 阶段意味着可能发生了内部重定向或这是第一次匹配 location。 之前设置的 content_handler(例如上个 location 指定的内容生成器)已经失效,必须复位, 后续根据新 location 重新确定。 uri_changed 用于在 location 匹配后判断是否需要重新匹配。 这里初始化为 0,待后续 rewrite 阶段再次标记。 意义:保证每次 location 匹配前都从一个干净的状态开始,避免残留配置干扰。

2 执行 location 匹配
rc=ngx_http_core_find_location(r);
调用核心函数进行 location 匹配, 根据请求的 URI 在 server 块内的所有 location 中寻找最佳匹配, 并更新 r->loc_conf 等配置指针

3 匹配出错
if(rc==NGX_ERROR){ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);returnNGX_OK;}
处理 location 查找内部错误 条件: location 匹配过程中发生不可恢复的错误。 动作: 调用 ngx_http_finalize_request 以 500 状态码终结请求, 并向引擎返回 NGX_OK 使其退出阶段循环。 意义: 快速失败,防止后续阶段操作无效数据,保证请求安全结束。

4 获取匹配到的 location 的核心配置
clcf=ngx_http_get_module_loc_conf(r,ngx_http_core_module);
获取匹配到的 location 的核心配置 从当前请求的 location 配置中提取 ngx_http_core_module 的配置结构。

5 检查 internal 访问限制
if(!r->internal&&clcf->internal){ngx_http_finalize_request(r,NGX_HTTP_NOT_FOUND);returnNGX_OK;}
检查 internal 访问限制 条件: !r->internal: 请求不是内部重定向产生的(即来自客户端的外部请求)。 clcf->internal: 匹配到的 location 配置了 internal; 指令,仅允许内部访问。 动作: 返回 404 NOT FOUND,并退出引擎。 意义: 实现访问控制,保护内部使用的路径(如 error_page 的转发目标)不被客户端直接请求。

6 应用 location 配置到请求
ngx_log_debug2(NGX_LOG_DEBUG_HTTP,r->connection->log,0,"using configuration \"%s%V\"",(clcf->noname?"*":(clcf->exact_match?"=":"")),&clcf->name);ngx_http_update_location_config(r);ngx_log_debug2(NGX_LOG_DEBUG_HTTP,r->connection->log,0,"http cl:%O max:%O",r->headers_in.content_length_n,clcf->client_max_body_size);
ngx_http_update_location_config 应用 location 配置到请求 作用: 将当前 location 下的各类配置 更新到请求结构体的相应字段。 意义: 确保 location 级别的指令能实际影响请求的处理行为, 因为许多指令的值是在请求运行中从 r 中读取的。

7 判断请求体是否过大
if(r->headers_in.content_length_n!=-1&&!r->discard_body&&clcf->client_max_body_size&&clcf->client_max_body_size<r->headers_in.content_length_n){ngx_log_error(NGX_LOG_ERR,r->connection->log,0,"client intended to send too large body: %O bytes",r->headers_in.content_length_n);r->expect_tested=1;(void)ngx_http_discard_request_body(r);ngx_http_finalize_request(r,NGX_HTTP_REQUEST_ENTITY_TOO_LARGE);returnNGX_OK;}
判断请求体是否过大 条件拆解: content_length_n != -1: 存在有效的 Content-Length 头部。 !r->discard_body: 没有在之前的处理中决定丢弃请求体(如已返回错误,可能已设置丢弃标志)。 clcf->client_max_body_size 非零: location 配置了最大 body 限制。 clcf->client_max_body_size < content_length_n: 声明的大小超过限制。 逻辑: 所有条件同时满足, 说明客户端意图发送的请求体超出允许范围,必须拒绝。 记录 body 过大错误日志 设置 expect_tested 标记 丢弃请求体并最终化请求
Expect: 100-continue 机制简介 当客户端发送一个带有请求体(如 POST)的 HTTP 请求时, 可能会先发送一个包含 Expect: 100-continue 的请求头。 此时,服务器需要在收到请求体之前决定是否接受该请求: 如果服务器愿意接收, 就回复 100 Continue, 客户端再发送请求体。 如果服务器拒绝(例如请求体过大、权限不足), 就回复一个最终的错误状态码(如 413、403),并关闭连接, 不再发送 100 Continue。 r->expect_tested 的含义 r->expect_tested 标志用来表明 “是否已经对 Expect: 100-continue 做出了最终决定”。 置 1 是向所有下游模块广播: “Expect 协商已跳过/已失效,直接走错误清理路径”。 它告诉底层 Body 处理模块:“请求已被拒,别等 100 了,直接丢弃缓冲区并清理连接”。

8 需要外部重定向
if(rc==NGX_DONE){ngx_http_clear_location(r);r->headers_out.location=ngx_list_push(&r->headers_out.headers);if(r->headers_out.location==NULL){ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);returnNGX_OK;}r->headers_out.location->hash=1;r->headers_out.location->next=NULL;ngx_str_set(&r->headers_out.location->key,"Location");if(r->args.len==0){r->headers_out.location->value=clcf->escaped_name;}else{len=clcf->escaped_name.len+1+r->args.len;p=ngx_pnalloc(r->pool,len);if(p==NULL){ngx_http_clear_location(r);ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);returnNGX_OK;}r->headers_out.location->value.len=len;r->headers_out.location->value.data=p;p=ngx_cpymem(p,clcf->escaped_name.data,clcf->escaped_name.len);*p++='?';ngx_memcpy(p,r->args.data,r->args.len);}ngx_http_finalize_request(r,NGX_HTTP_MOVED_PERMANENTLY);returnNGX_OK;}
#1 检查 ngx_http_core_find_location 的返回值是否为 NGX_DONE。 逻辑: 该返回值表示匹配到了一个需要外部重定向的情况。 最常见的是目录型 location(如 /images/), 但请求 URI 缺少尾部斜杠(如 /images),需要重定向添加 /。 意义: 这是 Nginx 实现 URI 标准化的重要手段,确保客户端访问路径的一致性。
#2 清理旧的 location 信息 作用: 释放之前可能为响应头 Location 分配的内存,并进行相关重置。 逻辑: 该函数会清理 r->headers_out.location 及相关字段, 为即将生成的新重定向头部做准备,防止内存泄漏和值冲突。 意义:保证每次重定向头部构造的独立性,避免残留信息干扰。
#3 分配新的响应头节点 作用: 在响应头链表中申请一个新的 ngx_table_elt_t 节点, 将其地址赋给 r->headers_out.location。 失败处理: 如果内存分配失败,直接以 500 错误终结请求, 并向引擎返回 NGX_OK 退出阶段循环。 意义: 为 Location 响应头提供存储载体, 是构造 301 响应的第一步。
#4 初始化 Location 头字段 作用: 设置该头部节点的基本属性。 hash = 1: 为头部名设置一个简单的哈希值 (通常用于后续的快速查找与比较,Nginx 中 Location 头哈希值固定为 1)。 next = NULL: 将下一个节点指针置空,确保该节点当前为链表末尾。 ngx_str_set 将 key 设置为字符串 "Location", 确定该头部是 HTTP 的 Location 响应头。 意义:完成头部节点的必要初始化,符合 Nginx 响应头管理规范。
#5 判断是否有查询参数(无参数) 作用: 如果原始请求没有查询参数(args 长度为 0), 直接将重定向的目标 URL 设置为 location 预计算好的转义名 escaped_name。 逻辑: clcf->escaped_name 是经过转义的 location 名称(包含添加的斜杠), 例如 /images/。直接复用该字符串,无需重新拼接,效率最高。 意义:零内存拷贝,快速生成重定向 URL,适用于大多数纯路径请求。
#6 有查询参数时的处理 原始请求携带查询参数, 需要将它们附加到重定向 URL 后面
计算所需长度并分配内存 len: 计算拼接后的总长度 = escaped_name 长度 + '?' 字符 + 参数字符串长度。 ngx_pnalloc: 从请求内存池分配 len 字节内存,失败返回 NULL。 失败处理: 内存分配失败时,调用 ngx_http_clear_location 清理已设置的响应头, 然后以 500 错误终结请求,返回 NGX_OK 退出。 意义:安全可靠地处理内存不足异常,避免半成品响应头被发送。
设置 Location 头值字段 作用: 将 value 的长度和数据指针分别设置为新分配的 len 和 p, 使 Location 头指向拼接后的字符串。 意义:建立响应头与字符串数据的关联。
拼接 URL ngx_cpymem: 将 escaped_name 的内容拷贝到 p,并返回拷贝后的尾部指针,实现追加。 *p++ = '?': 在路径末尾添加问号,作为路径与查询参数的分隔符。 ngx_memcpy: 将原始参数字符串拷贝到剩余空间,完成整个 URL 的拼接。 意义:完整、高效地构造包含原始查询参数的重定向目标 URL,符合 HTTP 标准对 301 重定向的要求,保留客户端请求信息。
ngx_http_finalize_request: 以 NGX_HTTP_MOVED_PERMANENTLY(301 状态码)终结当前请求, 该函数会负责发送响应头(包括刚设置的 Location 头)并结束请求。 return NGX_OK: 向阶段引擎返回 NGX_OK, 引擎收到后会退出 while 循环, 停止所有后续阶段处理。 意义: 这是目录重定向的最终出口, 保证了在发送 301 后请求不再进入后续阶段(如内容生成), 避免了错误的响应输出。

9 正常出口
r->phase_handler++;returnNGX_AGAIN;}
将请求推进到下一个处理阶段,并通知引擎继续执行 r->phase_handler 是当前请求在 phase_engine.handlers 数组中的索引。 这个数组按顺序排列了所有阶段的所有处理器(包括 checker 和 handler)。 在这里将其递增 1,意味着跳过当前 FIND_CONFIG 阶段的处理器项, 指向下一个阶段的第一个处理器, 也就是 NGX_HTTP_REWRITE_PHASE 的起始位置。 return NGX_AGAIN 返回 NGX_AGAIN 给阶段引擎 ngx_http_core_run_phases。 在引擎的主循环中: 由于返回的是 NGX_AGAIN(不是 NGX_OK), 引擎不会退出,而是继续下一轮循环。 下一轮循环会读取新的 r->phase_handler, 从而开始执行下一个阶段的 checker 和 handler。

http://www.jsqmd.com/news/923491/

相关文章:

  • 微信聊天记录永久保存指南:如何将珍贵对话转化为数字资产
  • 终极微信QQ防撤回指南:5步实现消息永久保留
  • Python之yabormeparser包语法、参数和实际应用案例
  • 如何快速实现AI智能图像分层:免费工具Layerdivider完整指南
  • 东莞市大岭山玥盛:龙岗胶合板木箱公司 - LYL仔仔
  • 告别License烦恼:一份给Aurix新手的Tasking TriCore环境自查清单
  • 乌鲁木齐企业选择一般纳税人还是小规模纳税人的经验分享 - 新疆全疆企业服务
  • Tinkercad Codeblocks实战:用可视化编程制作3D飞机起飞动画
  • TensorFlow.js 时间序列预测实战:从数据预处理到浏览器端模型部署
  • Xbox 360模拟器Xenia Canary实战指南:深度解析与专业配置方案
  • Gemini数据出境安全评估:7步完成跨境传输备案,避开92%企业踩过的雷区
  • AI瞄准系统:三档性能方案让游戏新手也能体验职业选手的精准度
  • 基于Arduino与涂鸦IoT平台打造智能植物监测系统
  • 如何在浏览器中免费编辑GPX文件:GPX Studio完全指南 [特殊字符]️
  • 番茄小说本地化收藏:告别网络依赖的数字阅读新方案
  • 揭秘谷歌Gemini首发公关战役:如何用3天引爆全球科技媒体头条
  • 基于Johnny-Five与Socket.io构建实时物联网系统:从硬件连接到Web交互
  • 零配置打包方案:5分钟将网页变应用的终极指南
  • 3步掌握YimMenu:GTA5最强免费保护与增强工具完全指南
  • FinalBurn Neo终极指南:如何在5分钟内搭建完美的街机游戏模拟环境
  • 如何在Web应用中实现专业的电子签名功能:Signature Pad深度解析
  • 为什么CPU 只有几十个通用寄存器?
  • 终极OBS背景移除指南:免费实现专业级绿幕效果
  • AI架构师面试问题与解答 - 机器学习基础篇
  • C++ STL 仿函数完全指南:从内置仿函数到自定义实现
  • GHelper深度解析:华硕笔记本终极性能优化实战手册
  • 到底为什么PHP要用PHP-FPM?
  • 跨平台资源下载神器:3分钟解锁全网视频音频图片下载新姿势
  • FlatLaf:Java Swing界面的现代美学革命与生产力提升终极方案
  • 2026年武夷山正规酒店怎么选?这6家本地人推荐 - charlieruizvin