《深入剖析ngx》——请求定位
1. location 指令 配置解析
1.1 指令格式
location配置支持如下格式,
location 的参数是 uri, 可以是模糊的,也可以是绝对的
1.2 配置解析——生成loc树
2949 static char *
2950 ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
2951 {
// 创建 loc 配置块
2976 for (i = 0; cf->cycle->modules[i]; i++) {
2977 if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
2978 continue;
2979 }
2980
2981 module = cf->cycle->modules[i]->ctx;
2982
2983 if (module->create_loc_conf) {
2984 ctx->loc_conf[cf->cycle->modules[i]->ctx_index] =
2985 module->create_loc_conf(c f);
2986 if (ctx->loc_conf[cf->cycle->modules[i]->ctx_index] == NULL) {
2987 return NGX_CONF_ERROR;
2988 }
2989 }
2990 }
2992 clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
2993 clcf->loc_conf = ctx->loc_conf;
。。。
// 将 clcf 加入 locations 队列
3127 if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
3128 return NGX_CONF_ERROR;
3129 }
3130 // 切换配置上下文,解析 location {} 内配置
3131 save = *cf;
3132 cf->ctx = ctx;
3133 cf->cmd_type = NGX_HTTP_LOC_CONF;
3134
3135 rv = ngx_conf_parse(cf, NULL);
以上 location 为 命名loc,
另外还有 未命名loc,即 使用 if, limit_except 指令 配置生成的location, 其 clcf->noname=1,这些loc会加入loc树,构成如下结构
同级的loc为一个节点,loc嵌套为子树
1.3 配置解析——优化loc树
为了提高效率,ngx对loc树进行合并裁剪
loc树裁剪前
裁剪后
数据结构
2. server定位
所谓server定位,就是找到 报文目的主机 相关的 配置上下文。
ngx 接受到TCP连接时,先从套接字获得目的地址,
ngx 支持虚拟主机,判断 报文的目的主机是哪台 虚拟主机时,必须分析 请求头,
但在解析 请求 前,必须设置 服务器配置上下文,
所以 ngx 使用 default server 作为预先配置
206 void
207 ngx_http_init_connection(ngx_connection_t *c)
208 {
234 if (port->naddrs > 1) {
235
241 // 获得目的地址
242 if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
243 ngx_http_close_connection(c);
244 return;
245 }
// 根据
268 default: /* AF_INET */
269 sin = (struct sockaddr_in *) c->local_sockaddr;
270
271 addr = port->addrs;
272
273 /* the last address is "*" */
274
275 for (i = 0; i < port->naddrs - 1; i++) {
276 if (addr[i].addr == sin->sin_addr.s_addr) {
277 break;
278 }
279 }
281 hc->addr_conf = &addr[i].conf;
282
283 break;
284 }
// 使用默认主机配置
304 /* the default server configuration for the address:port */
305 hc->conf_ctx = hc->addr_conf->default_server->ctx;
// 下一个事件处理为 ngx_http_wait_request_handler
325 rev->handler = ngx_http_wait_request_handler;
377 static void
378 ngx_http_wait_request_handler(ngx_event_t *rev)
379 {
// 构造报文
496 c->data = ngx_http_create_request(c);
// 解析报文
503 ngx_http_process_request_line(rev);
504 }
507 ngx_http_request_t *
508 ngx_http_create_request(ngx_connection_t *c)
509 {
514 r = ngx_http_alloc_request(c);
539 static ngx_http_request_t *
540 ngx_http_alloc_request(ngx_connection_t *c)
541 {
549 hc = c->data;
566 r->http_connection = hc;
567 r->signature = NGX_HTTP_MODULE;
568 r->connection = c;
569 // 设置 配置上下文,也就是找到 server
570 r->main_conf = hc->conf_ctx->main_conf;
571 r->srv_conf = hc->conf_ctx->srv_conf;
572 r->loc_conf = hc->conf_ctx->loc_conf;
ngx使用 default server 配置上下文,进行解析 报文,根据报文头 Host 字段,找虚拟机,更改当前请求的 server 配置上下文
ngx_http_process_request_line -> ngx_http_process_request_headers -> ngx_http_find_virtual_server
2284 static ngx_int_t
2285 ngx_http_find_virtual_server(ngx_connection_t *c,
2286 ngx_http_virtual_names_t *virtual_names, ngx_str_t *host,
2287 ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp)
2288 {
2295 cscf = ngx_hash_find_combined(&virtual_names->names,
2296 ngx_hash_key(host->data, host->len),
2297 host->data, host->len);
2298
2299 if (cscf) {
2300 *cscfp = cscf;
2301 return NGX_OK;
2302 }
2303
3. Location 定位
Location定位位于 http 处理 的 NGX_HTTP_FIND_CONFIG_PHASE 阶段
497 case NGX_HTTP_FIND_CONFIG_PHASE:
498 find_config_index = n;
499
500 ph->checker = ngx_http_core_find_config_phase;
501 n++;
502 ph++;
503
504 continue;
ngx 根据 r->uri 进行 location 定位,找到后修改 r->loc_conf
948 ngx_int_t
949 ngx_http_core_find_config_phase(ngx_http_request_t *r,
950 ngx_http_phase_handler_t *ph)
951 {
960 rc = ngx_http_core_find_location(r);
1393 static ngx_int_t
1394 ngx_http_core_find_location(ngx_http_request_t *r)
1395 {
1405
1406 pclcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1407
1408 rc = ngx_http_core_find_static_location(r, pclcf->static_locations);
1470 static ngx_int_t
1471 ngx_http_core_find_static_location(ngx_http_request_t *r,
1472 ngx_http_location_tree_node_t *node)
1473 {
1478 len = r->uri.len;
1479 uri = r->uri.data;
1483 for ( ;; ) {
1495 rc = ngx_filename_cmp(uri, node->name, n);
1496
1497 if (rc != 0) {
1498 node = (rc < 0) ? node->left : node->right;
1499
1500 continue;
1501 }
...
1503 if (len > (size_t) node->len) {
1504
1505 if (node->inclusive) {
1506
1507 r->loc_conf = node->inclusive->loc_conf; // 找到 loc 修改r->loc_conf
1508 rv = NGX_AGAIN;
1509
1510 node = node->tree;
1511 uri += n;
1512 len -= n;
1513
1514 continue;
1515 }
1516
1517 /* exact only */
1518
1519 node = node->right;
1520
1521 continue;
1522 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?