static char *
ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
{
char *rv;
void *mconf;
size_t len;
u_char *p;
ngx_uint_t i;
ngx_conf_t pcf;
ngx_http_module_t *module;
struct sockaddr_in *sin;
ngx_http_conf_ctx_t *ctx, *http_ctx;
ngx_http_listen_opt_t lsopt;
ngx_http_core_srv_conf_t *cscf, **cscfp;
ngx_http_core_main_conf_t *cmcf;
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
http_ctx = cf->ctx;
ctx->main_conf = http_ctx->main_conf;
/* the server{}'s srv_conf */
ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->srv_conf == NULL) {
return NGX_CONF_ERROR;
}
/* the server{}'s loc_conf */
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->loc_conf == NULL) {
return NGX_CONF_ERROR;
}
for (i = 0; cf->cycle->modules[i]; i++) {
if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
continue;
}
module = cf->cycle->modules[i]->ctx;
if (module->create_srv_conf) {
mconf = module->create_srv_conf(cf);
if (mconf == NULL) {
return NGX_CONF_ERROR;
}
ctx->srv_conf[cf->cycle->modules[i]->ctx_index] = mconf;
}
if (module->create_loc_conf) {
mconf = module->create_loc_conf(cf);
if (mconf == NULL) {
return NGX_CONF_ERROR;
}
ctx->loc_conf[cf->cycle->modules[i]->ctx_index] = mconf;
}
}
/* the server configuration context */
cscf = ctx->srv_conf[ngx_http_core_module.ctx_index];
cscf->ctx = ctx;
cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
cscfp = ngx_array_push(&cmcf->servers);
if (cscfp == NULL) {
return NGX_CONF_ERROR;
}
*cscfp = cscf;
/* parse inside server{} */
pcf = *cf;
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_SRV_CONF;
rv = ngx_conf_parse(cf, NULL);
*cf = pcf;
if (rv == NGX_CONF_OK && !cscf->listen) {
ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t));
p = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in));
if (p == NULL) {
return NGX_CONF_ERROR;
}
lsopt.sockaddr = (struct sockaddr *) p;
sin = (struct sockaddr_in *) p;
sin->sin_family = AF_INET;
#if (NGX_WIN32)
sin->sin_port = htons(80);
#else
sin->sin_port = htons((getuid() == 0) ? 80 : 8000);
#endif
sin->sin_addr.s_addr = INADDR_ANY;
lsopt.socklen = sizeof(struct sockaddr_in);
lsopt.backlog = NGX_LISTEN_BACKLOG;
lsopt.rcvbuf = -1;
lsopt.sndbuf = -1;
#if (NGX_HAVE_SETFIB)
lsopt.setfib = -1;
#endif
#if (NGX_HAVE_TCP_FASTOPEN)
lsopt.fastopen = -1;
#endif
lsopt.wildcard = 1;
len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
p = ngx_pnalloc(cf->pool, len);
if (p == NULL) {
return NGX_CONF_ERROR;
}
lsopt.addr_text.data = p;
lsopt.addr_text.len = ngx_sock_ntop(lsopt.sockaddr, lsopt.socklen, p,
len, 1);
if (ngx_http_add_listen(cf, cscf, &lsopt) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
return rv;
}
ngx_http_core_server
函数是 Nginx 在解析配置文件中 server{}
块时的核心处理函数
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
为
server{}
块的配置上下文分配内存
ngx_http_conf_ctx_t
是 Nginx HTTP 配置的核心结构体,用于存储server{}
块的配置上下文(包括main_conf
、srv_conf
、loc_conf
三个配置数组)
http_ctx = cf->ctx;
ctx->main_conf = http_ctx->main_conf;
在解析
server{}
块时,cf->ctx
指向的是全局的 HTTP 配置上下文(即main
级别的配置上下文)。通过赋值给
http_ctx
,将全局上下文保存到临时变量中,避免后续因cf->ctx
被修改而丢失对全局配置的引用。
http_ctx->main_conf
是全局 HTTP 配置中的main_conf
数组,存储所有 HTTP 模块的main
级配置。
ctx->main_conf
是当前server{}
块上下文中的main_conf
指针。通过直接赋值,使
server{}
块的main_conf
指向全局的main_conf
,实现配置继承
/* the server{}'s srv_conf */
ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->srv_conf == NULL) {
return NGX_CONF_ERROR;
}
为
server{}
块的srv_conf
数组分配内存
/* the server{}'s loc_conf */
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->loc_conf == NULL) {
return NGX_CONF_ERROR;
}
为
server{}
块的loc_conf
数组分配内存
for (i = 0; cf->cycle->modules[i]; i++) {
if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
continue;
}
遍历,跳过非NGX_HTTP_MODULE模块
module = cf->cycle->modules[i]->ctx;
获取模块的上下文
if (module->create_srv_conf) {
mconf = module->create_srv_conf(cf);
if (mconf == NULL) {
return NGX_CONF_ERROR;
}
ctx->srv_conf[cf->cycle->modules[i]->ctx_index] = mconf;
}
create_srv_conf
是模块定义的函数指针,用于创建该模块的server
级配置结构体
if (module->create_loc_conf) {
mconf = module->create_loc_conf(cf);
if (mconf == NULL) {
return NGX_CONF_ERROR;
}
ctx->loc_conf[cf->cycle->modules[i]->ctx_index] = mconf;
}
用于创建该模块的
location
级配置结构体
/* the server configuration context */
cscf = ctx->srv_conf[ngx_http_core_module.ctx_index];
cscf->ctx = ctx;
获取核心模块(
ngx_http_core_module
)的server
级配置结构体将
server{}
块的配置上下文(ctx
)关联到核心模块的配置结构体
cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
访问当前
server{}
块上下文中的main_conf
数组获取核心模块(
ngx_http_core_module
)的 main 级配置
ctx
是当前server{}
块的配置上下文
main_conf
,指向全局的main
级配置数组。该数组存储了所有 HTTP 模块的
main
级配置结构体指针配置继承 :
server{}
块通过main_conf
继承全局配置全局数据访问 :
main_conf
是全局唯一的,所有server{}
块共享同一份main_conf
。
cscfp = ngx_array_push(&cmcf->servers);
if (cscfp == NULL) {
return NGX_CONF_ERROR;
}
将当前
server{}
块的核心配置指针添加到全局服务器列表
cmcf->servers
是核心模块全局配置(ngx_http_core_main_conf_t
)中的动态数组,存储所有server{}
块的ngx_http_core_srv_conf_t
指针。
*cscfp = cscf;
*cscfp = cscf 是将cscf的值(即当前server的核心配置结构体指针)存储到动态数组中的新位置
将当前
server{}
块的核心配置指针赋值给动态数组中的新元素
/* parse inside server{} */
pcf = *cf;
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_SRV_CONF;
rv = ngx_conf_parse(cf, NULL);
*cf = pcf;
保存当前配置解析上下文的状态
将配置解析上下文切换为当前
server{}
块的上下文设置当前解析的指令类型为
server
级指令递归解析
server{}
块内部的配置指令恢复原始的配置解析上下文
进入 ngx_conf_parse
else if (cf->conf_file->file.fd != NGX_INVALID_FILE) {
type = parse_block;
进入这个条件
然后
for ( ;; ) {
rc = ngx_conf_read_token(cf);
循环,读取 token
接下来读到的是
listen 80
;作为结束
然后
rc = ngx_conf_handler(cf, rc);
处理当前读取的 token
进入 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_str_t *name;
ngx_command_t *cmd;
name = cf->args->elts;
found = 0;
当前要处理的指令是 listen
name->data=listen
for (i = 0; cf->cycle->modules[i]; i++) {
cmd = cf->cycle->modules[i]->commands;
if (cmd == NULL) {
continue;
}
for ( /* void */ ; cmd->name.len; cmd++) {
if (name->len != cmd->name.len) {
continue;
}
if (ngx_strcmp(name->data, cmd->name.data) != 0) {
continue;
}
循环,查找 listen 指令
直到
i=9
modules[9]->name=ngx_http_core_module
然后通过语法检查
接下来
else if (cf->ctx) {
confp = *(void **) ((char *) cf->ctx + cmd->conf);
if (confp) {
conf = confp[cf->cycle->modules[i]->ctx_index];
}
}
此时
**cmd->conf=8
ctx_index=0**
cmd->conf
是一个关键字段,用于定位指令对应的配置存储位置
cmd->conf
是ngx_command_t
结构体中的一个字段,表示 配置存储的偏移量 。它决定了该指令的配置值应被存储到哪个配置块(如main
、server
、location
等)的内存区域中。此时 cf->ctx 指向一个 ngx_http_conf_ctx_t 结构体
ngx_http_conf_ctx_t -CSDN博客
(char *) cf->ctx + cmd->conf
也就是跳过了 结构体中的第一个字段,指向结构体的第二个字段 srv_conf
srv_conf 用来
存储server 级别的配置数据 (当前正处于 server 块中)
接下来
rv = cmd->set(cf, cmd, conf);
此时的 cmd->set 是 ngx_http_core_module 的 listen指令的set
是 ngx_http_core_listen
ngx_http_core_listen-CSDN博客
if (rv == NGX_CONF_OK) {
return NGX_OK;
}
返回 NGX_OK
回到 ngx_conf_parse
rc = ngx_conf_read_token(cf);
继续 读取配置文件 接下来的 token
接下来要读取的 token 是 37行的
server_name localhost 以 ;为结束
server_name localhost;
是 Nginx 配置中的关键指令,用于定义虚拟主机(Virtual Host)的域名或标识符。它的核心作用是 根据 HTTP 请求的Host
头字段匹配对应的服务器配置块 ,从而确保 Nginx 能正确路由请求到目标服务
rc = ngx_conf_handler(cf, rc);
处理读取的 token
进入 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_str_t *name;
ngx_command_t *cmd;
name = cf->args->elts;
found = 0;
此时 name->data=server_name
此时要处理的指令是 server_name
for (i = 0; cf->cycle->modules[i]; i++) {
cmd = cf->cycle->modules[i]->commands;
if (cmd == NULL) {
continue;
}
for ( /* void */ ; cmd->name.len; cmd++) {
if (name->len != cmd->name.len) {
continue;
}
if (ngx_strcmp(name->data, cmd->name.data) != 0) {
continue;
}
found = 1;
遍历查找 server_name 指令
直到 i=9
modules[9]->name=ngx_http_core_module
在 ngx_http_core_module 模块中找到了 server_name 指令
cmd->name.data=server_name
然后通过语法检查之后
else if (cf->ctx) {
confp = *(void **) ((char *) cf->ctx + cmd->conf);
if (confp) {
conf = confp[cf->cycle->modules[i]->ctx_index];
}
}
**cmd->conf=8
ctx_index=0**
rv = cmd->set(cf, cmd, conf);
此时的 cmd->set 是 ngx_http_core_module 模块的 server_name 指令 的set 函数指针
ngx_http_core_server_name
ngx_http_core_server_name-CSDN博客
if (rv == NGX_CONF_OK) {
return NGX_OK;
}
返回 NGX_OK
回到 ngx_conf_parse
rc = ngx_conf_read_token(cf);
继续读取 token
跳过注释和空行 接下来是 43 行的
location / {
以{ 为结束
rc = ngx_conf_handler(cf, rc);
处理 token
进入 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_str_t *name;
ngx_command_t *cmd;
name = cf->args->elts;
found = 0;
此时 name->data=location
for (i = 0; cf->cycle->modules[i]; i++) {
cmd = cf->cycle->modules[i]->commands;
if (cmd == NULL) {
continue;
}
for ( /* void */ ; cmd->name.len; cmd++) {
if (name->len != cmd->name.len) {
continue;
}
if (ngx_strcmp(name->data, cmd->name.data) != 0) {
continue;
}
found = 1;
遍历查找 location 指令
直到
i=9
modules[9]->name=ngx_http_core_module
else if (cf->ctx) {
confp = *(void **) ((char *) cf->ctx + cmd->conf);
if (confp) {
conf = confp[cf->cycle->modules[i]->ctx_index];
}
}
cmd->conf=8
ctx_index=0
rv = cmd->set(cf, cmd, conf);
此时 是ngx_http_core_module 模块的 location 指令 的set 函数指针
是 ngx_http_core_location
if (rv == NGX_CONF_OK) {
return NGX_OK;
}
返回 NGX_OK
回到 ngx_conf_parse
rc = ngx_conf_read_token(cf);
继续读取 token
接下来读取的是
error_page 500 502 503 504 /50x.html
以 ;为结束
这行配置的作用是:当 Nginx 服务器遇到指定的 HTTP 错误状态码(500、502、503、504)时,自动将客户端请求重定向到自定义的错误页面/50x.html
,而不是显示默认的 Nginx 错误页面
error_page
这是 Nginx 的指令,用于定义当服务器发生错误时返回的自定义页面。
500 502 503 504
这些是 HTTP 状态码,分别表示:500 :内部服务器错误(Internal Server Error)。
502 :网关错误(Bad Gateway),通常由上游服务器(如 PHP、反向代理)响应无效内容导致。
503 :服务不可用(Service Unavailable),通常因服务器过载或维护触发。
504 :网关超时(Gateway Timeout),上游服务器未及时响应。
/50x.html
这是自定义错误页面的路径(相对于 Nginx 的根目录root
)。
rc = ngx_conf_handler(cf, rc);
处理读取的 token
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_str_t *name;
ngx_command_t *cmd;
name = cf->args->elts;
found = 0;
此时 name->data=error_page
当前要处理的指令是 error_page
for (i = 0; cf->cycle->modules[i]; i++) {
cmd = cf->cycle->modules[i]->commands;
if (cmd == NULL) {
continue;
}
for ( /* void */ ; cmd->name.len; cmd++) {
if (name->len != cmd->name.len) {
continue;
}
if (ngx_strcmp(name->data, cmd->name.data) != 0) {
continue;
}
found = 1;
循环查找 error_page 指令
直到
i=9
modules[9]->name=ngx_http_core_module
else if (cf->ctx) {
confp = *(void **) ((char *) cf->ctx + cmd->conf);
if (confp) {
conf = confp[cf->cycle->modules[i]->ctx_index];
}
}
获取对应的配置结构的指针
此时
cmd->conf=16
ctx_index=0
rv = cmd->set(cf, cmd, conf);
处理 token
此时 是 ngx_http_core_module 模块的 error_page 指令的 set
指向的是 ngx_http_core_error_page
if (rv == NGX_CONF_OK) {
return NGX_OK;
}
返回 NGX_OK