📋 整体流程概览
┌─────────────────────────────────────────────────────────────────┐
│ Nginx 启动与请求处理流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 【启动阶段】 │
│ 1. main() │
│ ↓ │
│ 2. ngx_init_cycle() ← 初始化周期结构 │
│ ↓ │
│ 3. ngx_conf_init() ← 创建配置解析上下文 │
│ ↓ │
│ 4. ngx_conf_parse() ← 解析配置文件 │
│ ↓ │
│ 5. ngx_conf_post_configuration() ← 配置后处理 │
│ ↓ │
│ 6. 创建监听 socket,fork worker 进程 │
│ │
│ 【请求处理阶段】 │
│ 1. ngx_worker_process_cycle() │
│ ↓ │
│ 2. ngx_event_loop() ← 事件循环 │
│ ↓ │
│ 3. ngx_http_process_request_line() ← 读取请求行 │
│ ↓ │
│ 4. ngx_http_process_request_headers() ← 读取请求头 │
│ ↓ │
│ 5. ngx_http_core_run_phases() ← 执行 HTTP 处理阶段 │
│ ↓ │
│ 6. 根据配置中的 location 匹配,调用相应 handler │
│ │
└─────────────────────────────────────────────────────────────────┘
一、配置文件加载到内存结构
1.1 核心数据结构
Nginx 使用 ngx_cycle_t 和 ngx_conf_t 两个核心结构体来管理配置:
| 结构体 | 作用 | 关键字段 |
|---|---|---|
ngx_cycle_t |
Nginx 运行周期结构,保存全局状态 |
conf_ctx - 所有模块的配置上下文pool - 内存池connections - 连接数组listening - 监听端口数组
|
ngx_conf_t |
配置解析上下文 |
cycle - 指向当前 cycleconf_file - 当前解析的文件handler - 配置项处理函数ctx - 模块配置上下文
|
1.2 配置解析入口 - ngx_conf_parse()
这是配置解析的核心函数,位于 src/core/ngx_conf_file.c:
/* * 配置文件解析主函数 * cf: 配置解析上下文 * filename: 配置文件路径 (可选,NULL 表示使用默认) */ char * ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) { u_char *p; char *rv; ngx_int_t rc; ngx_buf_t *buf; ngx_str_t s; ngx_conf_file_t *conf_file; /* 如果是首次解析,打开配置文件 */ if (filename) { cf->conf_file->file = ngx_open_file(filename->data, ...); if (cf->conf_file->file == NGX_INVALID_FILE) { return NGX_CONF_ERROR; } } /* 主解析循环:逐行读取配置文件 */ for ( ;; ) { /* 读取一行配置 */ rc = ngx_conf_read_token(cf); if (rc == NGX_ERROR) { return NGX_CONF_ERROR; } /* 解析完成 */ if (rc == NGX_DONE) { return NGX_CONF_OK; } /* 处理解析到的指令 */ rc = ngx_conf_handler(cf, last); if (rc == NGX_ERROR) { return NGX_CONF_ERROR; } } }
关键点:配置解析是逐行进行的,每行被解析为 token 序列,然后调用对应的 handler 函数处理。
1.3 配置项处理 - ngx_conf_handler()
该函数负责查找并调用对应指令的处理函数:
static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last) { char *rv; void *conf, **confp; ngx_uint_t i, found; ngx_cmd_t *cmd; found = 0; /* 遍历所有模块的命令,查找匹配的指令 */ for (i = 0; cf->cycle->modules[i]; i++) { cmd = cf->cycle->modules[i]->commands; if (cmd == NULL) { continue; } for ( ; cmd->name.len; cmd++) { /* 比较指令名称 */ if (cf->args->elts[0].len != cmd->name.len) { continue; } if (ngx_strcmp(cf->args->elts[0].data, cmd->name.data) != 0) { continue; } found = 1; break; } if (found) { break; } } /* 调用找到的命令处理函数 */ rv = cmd->set(cmd, conf, confp, cf->args); return (rv == NGX_CONF_OK) ? NGX_OK : NGX_ERROR; }
重要:每个配置指令(如
worker_processes、listen、root)都有对应的 set 函数,该函数负责将配置值存储到内存结构体中。
二、配置在内存中的存储结构
2.1 三层配置结构
Nginx HTTP 模块的配置分为三个层级,每个层级对应不同的结构体:
| 层级 | 结构体 | 作用域 | 示例指令 |
|---|---|---|---|
| Main | ngx_http_core_main_conf_t |
全局配置 | worker_processes, user |
| Srv | ngx_http_core_srv_conf_t |
server 块配置 | server_name, listen |
| Loc | ngx_http_core_loc_conf_t |
location 块配置 | root, proxy_pass |
┌─────────────────────────────────────────────────────────────┐
│ 配置内存结构层次图 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ngx_http_core_main_conf_t (全局) │
│ ├─ servers: array<ngx_http_core_srv_conf_t> │
│ ├─ phase_engine: 处理阶段引擎 │
│ └─ ... │
│ │
│ └─ ngx_http_core_srv_conf_t (server 块) │
│ ├─ server_names: array<server_name> │
│ ├─ locations: array<ngx_http_core_loc_conf_t> │
│ ├─ listen: 监听端口配置 │
│ └─ ... │
│ │
│ └─ ngx_http_core_loc_conf_t (location 块) │
│ ├─ root: 根目录路径 │
│ ├─ proxy_pass: 代理地址 │
│ ├─ handler: 请求处理函数指针 │
│ └─ ... │
│ │
└─────────────────────────────────────────────────────────────┘
2.2 location 配置示例 - ngx_http_core_location()
/* * 处理 location 块配置 * 当解析到 location /xxx { ... } 时调用 */ static char * ngx_http_core_location(ngx_conf_t *cf, ngx_cmd_t *cmd, void *conf) { ngx_http_core_srv_conf_t *cscf; ngx_http_core_loc_conf_t *clcf, *alcf; cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); /* 创建 location 配置结构 */ clcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t)); /* 解析 location 修饰符和路径 */ if (ngx_strcmp(value[1].data, "=") == 0) { clcf->name = value[2]; clcf->exact_match = 1; } else if (ngx_strcmp(value[1].data, "~") == 0) { clcf->name = value[2]; clcf->regex = 1; } else { clcf->name = value[1]; } /* 将 location 添加到 server 的 location 列表 */ if (cscf->locations == NULL) { cscf->locations = ngx_array_create(cf->pool, 1, sizeof(ngx_http_core_loc_conf_t *)); } clcfp = ngx_array_push(cscf->locations); *clcfp = clcf; /* 递归解析 location 块内的配置 */ rv = ngx_conf_parse(cf, NULL); return rv; }
三、请求处理时配置如何起作用
3.1 请求处理的 11 个阶段
HTTP 请求处理分为 11 个阶段,每个阶段都有对应的 handler,这些 handler 来自配置:
| 阶段 | 处理函数 | 典型用途 |
|---|---|---|
| 1. Post Read | ngx_http_core_post_read_phase |
请求读取后处理 |
| 2. Server Rewrite | ngx_http_core_rewrite_phase |
server 块重写 |
| 3. Find Config | ngx_http_core_find_config_phase |
查找匹配的 location |
| 4. Rewrite | ngx_http_core_rewrite_phase |
location 块重写 |
| 5. Post Rewrite | ngx_http_core_post_rewrite_phase |
重写后处理 |
| 6. Pre Access | ngx_http_core_pre_access_phase |
访问控制前处理 |
| 7. Access | ngx_http_core_access_phase |
访问权限检查 |
| 8. Post Access | ngx_http_core_post_access_phase |
访问控制后处理 |
| 9. Try Files | ngx_http_core_try_files_phase |
try_files 指令处理 |
| 10. Content | ngx_http_core_content_phase |
生成响应内容 |
| 11. Log | ngx_http_core_log_phase |
记录访问日志 |
3.2 关键:查找匹配的 location
在 Find Config 阶段,Nginx 根据请求 URI 查找匹配的 location 配置:
/* * 查找配置 - 第 3 阶段 * 根据请求 URI 找到对应的 location 配置 */ static void ngx_http_core_find_config_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) { u_char *p; size_t len; ngx_http_core_loc_conf_t *clcf; r->content_handler = NULL; r->uri_changed = 0; /* 核心:根据 URI 查找匹配的 location */ clcf = ngx_http_core_find_location(r); r->loc_conf = clcf->loc_conf; /* 检查请求方法是否允许 */ if ((r->method & clcf->limit_except) == 0) { r->main->count++; ngx_http_internal_redirect(r, clcf->name, NULL); return; } /* 设置内容处理 handler */ r->content_handler = clcf->handler; ph++; r->phase_handler = ph - r->phase_engine.handlers; r->write_event_handler(r); }
关键点:
ngx_http_core_find_location() 函数会遍历 server 块下的所有 location,根据匹配规则(精确匹配、前缀匹配、正则匹配)找到最合适的 location 配置。
3.3 内容生成阶段 - 配置中的 handler 如何被调用
/* * 内容生成阶段 - 第 10 阶段 * 调用 location 配置中设置的 handler 生成响应 */ static void ngx_http_core_content_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) { size_t root; ngx_int_t rc; ngx_http_core_loc_conf_t *clcf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); /* 如果 location 设置了 handler,直接调用 */ if (r->content_handler) { r->write_event_handler = ngx_http_request_empty_handler; rc = r->content_handler(r); return; } /* 没有 handler 时,尝试作为静态文件处理 */ if (clcf->root.len == 0) { ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND); return; } /* 拼接文件路径并返回文件内容 */ rc = ngx_http_map_uri_to_path(r, &path, &root, 0); if (rc == NGX_ERROR) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } ngx_http_finalize_request(r, ngx_http_static_handler(r)); }
handler 的来源:不同的模块会注册不同的 handler。例如:
proxy_pass→ngx_http_proxy_handlerfastcgi_pass→ngx_http_fastcgi_handlerreturn→ngx_http_return_handler- 无特殊指令 → 静态文件处理
四、完整示例:从配置到代码执行
4.1 配置示例
# nginx.conf http { server { listen 80; server_name example.com; # location 1: 静态文件 location /static/ { root /var/www; } # location 2: 反向代理 location /api/ { proxy_pass http://backend:8080; } # location 3: 精确匹配 location = /health { return 200 "OK"; } } }
┌─────────────────────────────────────────────────────────────────┐
│ 配置解析与内存结构对应关系 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 配置文件 内存结构 │
│ ┌──────────────┐ ┌─────────────────────────────┐ │
│ │ server { │──────────▶│ ngx_http_core_srv_conf_t │ │
│ │ listen 80; │ │ ├─ port = 80 │ │
│ │ ... │ │ ├─ server_name = ... │ │
│ │ │ │ └─ locations[] = [...] │ │
│ │ location │ │ │ │ │
│ │ /static/ { │──────────▶│ ├─[0]─▶ clcf: │ │
│ │ root │ │ ├─ name = "/static/" │
│ │ /var/www; │ │ ├─ root = "/var/www" │
│ │ } │ │ └─ handler = static │
│ │ │ │ │ │ │
│ │ location │ │ ├─[1]─▶ clcf: │ │
│ │ /api/ { │──────────▶│ ├─ name = "/api/" │
│ │ proxy_pass │ │ └─ handler = proxy │
│ │ ...; │ │ │ │ │
│ │ } │ │ └─[2]─▶ clcf: │ │
│ │ │ │ ├─ name = "/health" │
│ │ location │ │ ├─ exact_match = 1 │
│ │ = /health { │──────────▶│ └─ handler = return │
│ │ return 200 │ │ │ │
│ │ "OK"; │ └─────────────────────────────┘ │
│ │ } │ │
│ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
4.2 请求处理流程示例
当请求 GET /api/users 到达时:
| 步骤 | 函数 | 操作 |
|---|---|---|
| 1 | ngx_http_process_request_line() |
解析请求行,得到 GET /api/users HTTP/1.1 |
| 2 | ngx_http_process_request_headers() |
解析请求头 |
| 3 | ngx_http_core_find_config_phase() |
查找匹配的 location → 找到 /api/ |
| 4 | ngx_http_core_access_phase() |
执行访问控制检查 |
| 5 | ngx_http_core_content_phase() |
调用 proxy_handler 处理请求 |
| 6 | ngx_http_proxy_handler() |
向后端 http://backend:8080/api/users 转发请求 |
五、关键源码文件索引
| 文件路径 | 作用 | 关键函数 |
|---|---|---|
src/core/ngx_conf_file.c |
配置文件解析核心 | ngx_conf_parse(), ngx_conf_handler() |
src/core/ngx_cycle.c |
运行周期管理 | ngx_init_cycle() |
src/http/ngx_http_core_module.c |
HTTP 核心模块 | ngx_http_core_location(), ngx_http_core_find_location() |
src/http/ngx_http_request.c |
请求处理 | ngx_http_process_request(), ngx_http_core_run_phases() |
src/http/ngx_http_core_module.h |
HTTP 核心结构定义 | ngx_http_core_loc_conf_t, ngx_http_phase_t |
💡 学习建议
- 阅读源码时,建议从
ngx_conf_parse()入手,理解配置解析流程 - 重点关注配置值如何存储到结构体中,以及在请求处理时如何被读取使用
- 使用 GDB 或打印日志跟踪关键函数的执行路径
- 结合 Nginx 源码中的注释(英文注释通常更详细)一起阅读