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

ngx_http_create_locations_list

1 定义

ngx_http_create_locations_list 函数 定义在 ./nginx-1.24.0/src/http/ngx_http.c
staticvoidngx_http_create_locations_list(ngx_queue_t*locations,ngx_queue_t*q){u_char*name;size_tlen;ngx_queue_t*x,tail;ngx_http_location_queue_t*lq,*lx;if(q==ngx_queue_last(locations)){return;}lq=(ngx_http_location_queue_t*)q;if(lq->inclusive==NULL){ngx_http_create_locations_list(locations,ngx_queue_next(q));return;}len=lq->name->len;name=lq->name->data;for(x=ngx_queue_next(q);x!=ngx_queue_sentinel(locations);x=ngx_queue_next(x)){lx=(ngx_http_location_queue_t*)x;if(len>lx->name->len||ngx_filename_cmp(name,lx->name->data,len)!=0){break;}}q=ngx_queue_next(q);if(q==x){ngx_http_create_locations_list(locations,x);return;}ngx_queue_split(locations,q,&tail);ngx_queue_add(&lq->list,&tail);if(x==ngx_queue_sentinel(locations)){ngx_http_create_locations_list(&lq->list,ngx_queue_head(&lq->list));return;}ngx_queue_split(&lq->list,x,&tail);ngx_queue_add(locations,&tail);ngx_http_create_locations_list(&lq->list,ngx_queue_head(&lq->list));ngx_http_create_locations_list(locations,x);}
`ngx_http_create_locations_list` 函数的作用是: 将 Nginx 配置中线性排列的 location 列表, 按照路径前缀的包含关系递归拆分为多级嵌套的树形结构, 建立层次化的 location 组织关系。

2 详解

1 函数签名

staticvoidngx_http_create_locations_list(ngx_queue_t*locations,ngx_queue_t*q)
参数 ngx_queue_t *locations 当前正在处理的 location 链表的头节点(或哨兵节点)。 ngx_queue_t *q 它是 locations 链表中的一个节点。 函数会检查 q 所代表的 location 配置是否具有“包含性”(inclusive)。 如果 q 可以作为父节点,函数会遍历 q 之后的节点,寻找属于 q 的子节点,并将它们挂载到 q 下。 它是递归处理的起点,处理完 q 的子树后,函数会继续处理链表中的后续节点。
返回值 void:函数不返回任何值

2 逻辑流程

1 局部变量

1 局部变量 2 边界检查 3 判断当前 location 是否具有“包容”子 location 的能力 4 遍历查找相同前缀的节点 5 检查当前 location 是否真的拥有子节点 6 分割相同前缀的节点并挂载到当前节点下形成层级结构 7 处理后续节点
{u_char*name;size_tlen;ngx_queue_t*x,tail;ngx_http_location_queue_t*lq,*lx;

2 边界检查
if(q==ngx_queue_last(locations)){return;}
已经是最后一个节点 后面没有节点需要处理了

3 判断当前 location 是否具有“包容”子 location 的能力
lq=(ngx_http_location_queue_t*)q;if(lq->inclusive==NULL){ngx_http_create_locations_list(locations,ngx_queue_next(q));return;}
如果 inclusive == NULL, 则当前 location 不会对后续元素产生“归属”关系,无需构建子列表。 递归调用,处理下一个节点

4 遍历查找相同前缀的节点
len=lq->name->len;name=lq->name->data;for(x=ngx_queue_next(q);x!=ngx_queue_sentinel(locations);x=ngx_queue_next(x)){lx=(ngx_http_location_queue_t*)x;if(len>lx->name->len||ngx_filename_cmp(name,lx->name->data,len)!=0){break;}}
#1 获取当前 location 的名称长度和指针
#2 从当前 location 之后开始, 逐个检查后续的 location, 直到遇到第一个 不满足前缀匹配条件 的元素或到达队列末尾。
#3 判断当前检查的 location 是否前缀匹配 匹配条件有两个,必须 同时满足 才认为是匹配的(继续循环); 如果 任一条件不满足,则执行 break 退出循环。 条件一:len > lx->name->len 如果当前 location 的名称长度 大于 后续 location 的名称长度, 则不可能前缀匹配(因为后续 location 比当前还短,无法包含当前的前缀)。 条件二:ngx_filename_cmp(name, lx->name->data, len) != 0 调用 ngx_filename_cmp 比较两个字符串的前 len 个字符是否相等。 ngx_filename_cmp 是 Nginx 内部用于路径比较的函数, 如果前 len 个字符不相同,则不是前缀匹配。 若上述任一条件为真,则 break 退出循环。 若两个条件都不成立(即 len <= lx->name->len 且前 len 个字符相等), 则当前检查的 location 是当前 location 的 前缀匹配子节点,循环继续检查下一个后续元素。 循环结束后的状态: 当遇到第一个 不满足前缀匹配 的元素时,break 跳出循环,此时 x 指向该不匹配的元素(或哨兵)。 所有从 ngx_queue_next(q) 开始 到 x 之前 的元素(即已经遍历过的那些)都是前缀匹配的, 应成为当前 location 的子节点。 而 x 及其之后的元素则不属于当前 location 的子节点, 后续代码会将它们从当前队列中拆分出来

5 检查当前 location 是否真的拥有子节点
q=ngx_queue_next(q);if(q==x){ngx_http_create_locations_list(locations,x);return;}
x 是前面 for 循环中找到的第一个不满足前缀匹配的节点(或队列哨兵)。 如果 q == x,说明从当前 location 的下一个节点开始,第一个节点就已经不匹配了。 说明在原父节点和边界 x 之间没有任何节点 换句话说,没有任何节点可以作为当前 location 的子节点。 为什么可能相等: 因为 for 循环的条件是从 ngx_queue_next(q) 开始遍历, 如果第一个元素就不满足匹配条件,循环会立即 break, 此时 x 就等于 ngx_queue_next(q)(即新的 q)。

6 分割相同前缀的节点 并挂载到当前节点下形成层级结构
ngx_queue_split(locations,q,&tail);ngx_queue_add(&lq->list,&tail);if(x==ngx_queue_sentinel(locations)){ngx_http_create_locations_list(&lq->list,ngx_queue_head(&lq->list));return;}ngx_queue_split(&lq->list,x,&tail);ngx_queue_add(locations,&tail);ngx_http_create_locations_list(&lq->list,ngx_queue_head(&lq->list));
#1 将主链表 locations 在节点 q 处切割成两个独立的链表
#2 将切割出来的 tail 链表添加到当前父节点 lq 的子列表 lq->list 中 层级挂载:正式建立父子关系。 原本平级的节点,现在在逻辑上成为了当前 location 的子节点集合
#3 判断之前找到的边界节点 x 是否是主链表的哨兵节点(头节点)。 如果 x 等于哨兵节点,说明之前的循环一直遍历到了链表尽头都没有遇到不匹配的节点 这意味着当前父节点之后的所有剩余节点都是它的子节点,不存在“兄弟节点”或“无关节点”。 优化路径:既然没有无关节点需要归还给主链表,就可以跳过后续的“再次切割”逻辑,直接处理子列表 递归调用当前函数,整理刚刚挂载好的子列表 当前层级的任务已全部完成 return
#4 将当前父节点的子列表 lq->list 在节点 x 处再次切割 将不属于当前子树的节点分离到 tail 中 将切割出来的 tail 链表(非子节点部分)重新添加回主链表 locations 的末尾
#5 递归调用当前函数,处理子列表

7 处理后续节点
ngx_http_create_locations_list(locations,x);}
递归调用 它负责继续处理主链表中剩余的节点,完成整个 location 树的构建

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

相关文章:

  • 佛山哪里能找到不会出现水纹烂斑的隔热条厂家 - 工业品牌热点
  • 用QMK固件打造你的专属宏键盘:从配置到实战案例
  • 2026年杜兰小麦粉排行:国产VS进口,谁更适合你的生产线? - 速递信息
  • Sonobuoy高级用例:工作负载调试与性能分析实战
  • 2026年铝镁锰板厂家排名,常州泰州靠谱的铝镁锰板制造商大盘点 - mypinpai
  • 洛谷 P2014:[CTSC1997] 选课 ← 有依赖的背包问题
  • PP-DocLayoutV3与.NET生态集成:开发C#桌面端文档处理工具
  • 旧Mac升级与macOS支持完全指南:开源系统优化工具实现老旧Mac焕新
  • Ubuntu系统资源监控实战:从命令行到图形化工具全解析
  • 2026年北京旅游服务公司Top10,含体育旅游活动的公司推荐 - mypinpai
  • 沈北汽车贴膜好去处:2026年口碑之选,汽车车衣/改色膜/汽车贴膜/隐形车衣/沈北车衣/车衣改色,汽车贴膜品牌联系方式 - 品牌推荐师
  • 如何用TradingAgents-CN构建AI驱动的智能投顾系统?从多智能体协作到实战交易决策
  • 深圳鉴定费用全景解析:高端腕表真伪鉴别、价值评估的成本逻辑与行业实践 - 时光修表匠
  • 阶段一AI基础认知
  • 如何在AMD 780M APU上实现2-3倍AI性能提升?ROCmLibs优化库完全指南
  • 集团企业发票管理难?一招实现全流程集中管控
  • 大家公认的好用卫生巾品牌有哪些?2026口碑实测:奈丝公主凭细节设计圈粉 - 华Sir1
  • 高效智能转换方案:B站缓存视频一键处理实战指南
  • 2026年 包装袋厂家推荐排行榜:医药医疗包装袋、异形袋、真空袋、吸嘴袋等塑料包装袋源头企业实力解析与选购指南 - 品牌企业推荐师(官方)
  • P14464 海底列車(collapse)
  • 2026年市场口碑好的小龙虾筛选设备厂家推荐,小龙虾分选机/小龙虾筛选机/小龙虾筛选设备,小龙虾筛选设备供应商哪个好 - 品牌推荐师
  • 超越U-Net:拆解Cellpose如何用‘图像风格’和残差块实现通用分割
  • 模拟面试回答第十七问:垃圾判定算法
  • 2026商务全自动咖啡机选购指南:高效省心选机攻略 - 品牌2026
  • 3步掌握AI模型训练:让新手也能玩转个性化Stable Diffusion模型
  • 称重分拣装箱设备PLC数据采集解决方案
  • 数据字典+JWT+权限控制(RBAC)
  • 2026年高速投包机厂家推荐:广州辐艾达智能设备,碗面/杯面/泡面等全系机型供应 - 品牌推荐官
  • 说说深圳摩天智能装备创新能力如何,与对手相比谁更靠谱? - 工业设备
  • 清远鸡常见问题解答:腌制烹饪全攻略 - 速递信息