ngx_http_core_server

复制代码
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_confsrv_confloc_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->confngx_command_t 结构体中的一个字段,表示 配置存储的偏移量 。它决定了该指令的配置值应被存储到哪个配置块(如 mainserverlocation 等)的内存区域中。

此时 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

ngx_http_core_location-CSDN博客

复制代码
            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

ngx_http_core_error_page-CSDN博客

复制代码
            if (rv == NGX_CONF_OK) {
                return NGX_OK;
            }

返回 NGX_OK


相关推荐
代码or搬砖31 分钟前
Nginx详讲
运维·nginx·dubbo
Evan芙6 小时前
Nginx 平滑升级
数据库·nginx·ubuntu
Evan芙11 小时前
Nginx 安装教程(附Nginx编译安装脚本)
windows·nginx·postgresql
invicinble12 小时前
nginx的基本认识
运维·nginx
爆肝疯学大模型12 小时前
http转https,免费快速申请证书并实现nginx配置
nginx·http·https
qinyia12 小时前
通过 Wisdom SSH AI 助手部署和配置 Nginx Web 服务器
人工智能·nginx·ssh
嘻哈baby12 小时前
Nginx反向代理与负载均衡实战指南
运维·nginx·负载均衡
二哈喇子!1 天前
openFuyao 容器平台快速入门:Nginx 应用部署全流程实操
运维·nginx·openfuyao
J2虾虾1 天前
上传文件出现“ 413 Request Entity Too Large“错误
nginx
枫叶梨花1 天前
Nginx HTTPS代理大文件加载失败的排查与解决方案
nginx