Nginx構成分析

WBOY
リリース: 2016-08-08 09:31:25
オリジナル
946 人が閲覧しました

概要

前回の記事では『 Nginx の起動初期化プロセス」では、Nginx の起動プロセスを簡単に紹介し、その起動プロセスのソース コードを分析します。起動プロセスには、関数 ngx_init_cycle() を呼び出すという非常に重要なステップがあります。この関数の呼び出しにより、構成分析用のインターフェイスが提供されます。構成分析インターフェイスは、データの準備段階と構成分析段階の 2 つの段階に分けることができます。解析段階では、次の関数を呼び出します。設定ファイルを解析する際の各ディレクティブの属性。これは、

Nginx

プログラム内で非常に重要なデータ構造です。

src/core/ngx_conf_file.h
    /* 配置文件解析 */  
    if (ngx_conf_param(&conf) != NGX_CONF_OK) {/* 带有命令行参数'-g' 加入的配置 */  
        environ = senv;  
        ngx_destroy_cycle_pools(&conf);  
        return NULL;  
    }  
  
    if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {/* 解析配置文件*/  
        environ = senv;  
        ngx_destroy_cycle_pools(&conf);  
        return NULL;  
    }  
ログイン後にコピー
  • 設定ファイル。情報
  • conf_file
  • conf_file

    は、

    Nginx

    設定ファイルの関連情報を保存します。

    ngx_conf_file_t 構造の定義は次のとおりです:

    /* 解析配置时所使用的结构体 */
    struct ngx_conf_s {
        char                 *name;     /* 当前解析到的指令 */
        ngx_array_t          *args;     /* 当前指令所包含的所有参数 */
    
        ngx_cycle_t          *cycle;    /* 待解析的全局变量ngx_cycle_t */
        ngx_pool_t           *pool;     /* 内存池 */
        ngx_pool_t           *temp_pool;/* 临时内存池,分配一些临时数组或变量 */
        ngx_conf_file_t      *conf_file;/* 待解析的配置文件 */
        ngx_log_t            *log;      /* 日志信息 */
    
        void                 *ctx;      /* 描述指令的上下文 */
        ngx_uint_t            module_type;/* 当前解析的指令的模块类型 */
        ngx_uint_t            cmd_type; /* 当前解析的指令的指令类型 */
    
        ngx_conf_handler_pt   handler;  /* 模块自定义的handler,即指令自定义的处理函数 */
        char                 *handler_conf;/* 自定义处理函数需要的相关配置 */
    };
    
    ログイン後にコピー
    構成コンテキスト

    ctx Nginx 構成ファイルはブロックで構成されます。一般的なものには、http
    ブロック、

    server

    ブロック、および location ブロックが含まれます。

    アップストリーム

    ブロックやメールブロックなど。このような各構成ブロックはスコープを表します。上位レベルの構成ブロックのスコープには、複数の下位レベルの構成ブロックのスコープが含まれます。これは、スコープのネスト現象です。このようにして、構成ファイル内の多くのディレクティブが同時に複数のスコープに含まれるようになります。たとえば、http ブロック内の命令は、http ブロック、

    server

    ブロック、location ブロックの 3 つのスコープに同時に存在する可能性があります。

    Nginx プログラムが構成ファイルを解析するとき、各命令はそれが属するスコープを記録する必要があり、構成ファイルのコンテキスト ctx 変数は現在の命令が属するスコープを保存するために使用されます。 Nginx 構成ファイルのさまざまな構成ブロックのうち、http ブロックには、ストレージ構造の点でより複雑なサブ構成ブロックを含めることができます。 命令 pType の異なる命令タイプ Nginx プログラムは、マクロの形式で異なるソース dock ファイルで定義されます。 これらは、core タイプのモジュールによってサポートされる命令タイプです。 NGX_DIRECT_CONF クラス命令は、Nginx プログラムが設定解析関数に入る前に初期化されているため、設定解析関数に入った後、設定ファイルの構造から直接解析して実際のデータ構造に保存できます。これらは通常、構成ブロックの外側にあり、構成ファイルのグローバル ブロック部分にある命令を指します。

    NGX_MAIN_CONF

    クラスの命令には、eventhttpmailupstream およびその他の構成ブロックを形成できる命令が含まれます。これらには独自の初期化関数がありません。

    Nginx

    プログラムが構成ファイルを解析するときに NGX_MAIN_CONF クラス命令に遭遇すると、次のレベルの命令の解析に移行します。

    以下は、

    eventタイプのモジュールによってサポートされる命令タイプです。

    typedef struct {
        ngx_file_t            file;     /* 文件的属性 */
        ngx_buf_t            *buffer;   /* 文件的内容 */
        ngx_uint_t            line;     /* 文件的行数 */
    } ngx_conf_file_t;
    ログイン後にコピー
    以下は、http タイプのモジュールでサポートされている命令タイプであり、ファイルで定義されています: src/http/ngx_http_config.h
    #define NGX_DIRECT_CONF            0x00010000  
    #define NGX_MAIN_CONF              0x01000000  
    #define NGX_ANY_CONF               0x0F000000 
    ログイン後にコピー
    一般的なモジュール構成解析 構成解析モジュールは次のとおりです。 src/core/ngx_conf_file.cに実装されています。モジュールが提供するインターフェース関数は主に ngx_conf_parse です。さらに、このモジュールは、コマンドラインから渡された設定を解析するために使用される別のインターフェース ngx_conf_param を提供します。このインターフェースは ngx_conf_parse のラッパーでもあります。まず、次のように定義されている構成解析関数 ngx_conf_parse を見てみましょう:
    #define NGX_EVENT_CONF            0x02000000 
    ログイン後にコピー
    構成解析関数のソース コードから、この関数が構文解析と命令解析の 2 つの段階に分かれていることがわかります。 。構文分析は、
    ngx_conf_read_token() 関数によって完了します。コマンド解析には 2 つの方法があります。1 つは Nginx の組み込みコマンド解析メカニズムで、もう 1 つはカスタム コマンド解析メカニズムです。カスタム命令解析のソース コードは次のとおりです。
    #define NGX_HTTP_MAIN_CONF          0x02000000  
    #define NGX_HTTP_SRV_CONF           0x04000000  
    #define NGX_HTTP_LOC_CONF           0x08000000  
    #define NGX_HTTP_UPS_CONF           0x10000000  
    #define NGX_HTTP_SIF_CONF           0x20000000  
    #define NGX_HTTP_LIF_CONF           0x40000000  
    #define NGX_HTTP_LMT_CONF           0x80000000  
    ログイン後にコピー
    そして、
    Nginx

    の組み込み解析メカニズムは、関数ngx_conf_handler()によって実装されます。その定義は次のとおりです:

    /*
     * 函数功能:配置文件解析;
     * 支持三种不同的解析类型:
     * 1、解析配置文件;
     * 2、解析block块设置;
     * 3、解析命令行配置;
     */
    char *
    ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
    {
        char             *rv;
        ngx_fd_t          fd;
        ngx_int_t         rc;
        ngx_buf_t         buf;
        ngx_conf_file_t  *prev, conf_file;
        enum {
            parse_file = 0,
            parse_block,
            parse_param
        } type;
    
    #if (NGX_SUPPRESS_WARN)
        fd = NGX_INVALID_FILE;
        prev = NULL;
    #endif
    
        if (filename) {/* 若解析的是配置文件 */
    
            /* open configuration file */
    
            /* 打开配置文件 */
            fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
            if (fd == NGX_INVALID_FILE) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
                                   ngx_open_file_n " \"%s\" failed",
                                   filename->data);
                return NGX_CONF_ERROR;
            }
    
            prev = cf->conf_file;
    
            cf->conf_file = &conf_file;
    
            if (ngx_fd_info(fd, &cf->conf_file->file.info) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
                              ngx_fd_info_n " \"%s\" failed", filename->data);
            }
    
            cf->conf_file->buffer = &buf;
    
            buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log);
            if (buf.start == NULL) {
                goto failed;
            }
    
            buf.pos = buf.start;
            buf.last = buf.start;
            buf.end = buf.last + NGX_CONF_BUFFER;
            buf.temporary = 1;
    
            /* 复制文件属性及文件内容 */
            cf->conf_file->file.fd = fd;
            cf->conf_file->file.name.len = filename->len;
            cf->conf_file->file.name.data = filename->data;
            cf->conf_file->file.offset = 0;
            cf->conf_file->file.log = cf->log;
            cf->conf_file->line = 1;
    
            type = parse_file;  /* 解析的类型是配置文件 */
    
        } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) {
    
            type = parse_block; /* 解析的类型是block块 */
    
        } else {
            type = parse_param; /* 解析的类型是命令行配置 */
        }
    
    
        for ( ;; ) {
            /* 语法分析函数 */
            rc = ngx_conf_read_token(cf);
    
            /*
             * ngx_conf_read_token() may return
             *
             *    NGX_ERROR             there is error
             *    NGX_OK                the token terminated by ";" was found
             *    NGX_CONF_BLOCK_START  the token terminated by "{" was found
             *    NGX_CONF_BLOCK_DONE   the "}" was found
             *    NGX_CONF_FILE_DONE    the configuration file is done
             */
    
            if (rc == NGX_ERROR) {
                goto done;
            }
    
            /* 解析block块设置 */
            if (rc == NGX_CONF_BLOCK_DONE) {
    
                if (type != parse_block) {
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");
                    goto failed;
                }
    
                goto done;
            }
    
            /* 解析配置文件 */
            if (rc == NGX_CONF_FILE_DONE) {
    
                if (type == parse_block) {
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                       "unexpected end of file, expecting \"}\"");
                    goto failed;
                }
    
                goto done;
            }
    
            if (rc == NGX_CONF_BLOCK_START) {
    
                if (type == parse_param) {
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                       "block directives are not supported "
                                       "in -g option");
                    goto failed;
                }
            }
    
            /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */
    
            /* 自定义指令处理函数 */
            if (cf->handler) {
    
                /*
                 * the custom handler, i.e., that is used in the http's
                 * "types { ... }" directive
                 */
    
                if (rc == NGX_CONF_BLOCK_START) {
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\"");
                    goto failed;
                }
    
                /* 命令行配置处理函数 */
                rv = (*cf->handler)(cf, NULL, cf->handler_conf);
                if (rv == NGX_CONF_OK) {
                    continue;
                }
    
                if (rv == NGX_CONF_ERROR) {
                    goto failed;
                }
    
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv);
    
                goto failed;
            }
    
    
            /* 若自定义指令处理函数handler为NULL,则调用Nginx内建的指令解析机制 */
            rc = ngx_conf_handler(cf, rc);
    
            if (rc == NGX_ERROR) {
                goto failed;
            }
        }
    
    failed:
    
        rc = NGX_ERROR;
    
    done:
    
        if (filename) {/* 若是配置文件 */
            if (cf->conf_file->buffer->start) {
                ngx_free(cf->conf_file->buffer->start);
            }
    
            if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                              ngx_close_file_n " %s failed",
                              filename->data);
                return NGX_CONF_ERROR;
            }
    
            cf->conf_file = prev;
        }
    
        if (rc == NGX_ERROR) {
            return NGX_CONF_ERROR;
        }
    
        return NGX_CONF_OK;
    }
    
    ログイン後にコピー

    HTTP モジュール構成解析 ここでの主な構造は

    ngx_command_t

    です。この構造は「Nginxモジュール開発」の記事で紹介しましたが、その定義は次のとおりです。 :

    struct ngx_command_s {  
        /* 配置项名称 */  
        ngx_str_t             name;  
        /* 配置项类型,type将指定配置项可以出现的位置以及携带参数的个数 */  
        ngx_uint_t            type;  
        /* 处理配置项的参数 */  
        char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);  
        /* 在配置文件中的偏移量,conf与offset配合使用 */  
        ngx_uint_t            conf;  
        ngx_uint_t            offset;  
        /* 配置项读取后的处理方法,必须指向ngx_conf_post_t 结构 */  
        void                 *post;  
    }; 
    
    ログイン後にコピー

            若在上面的通用配置解析中,定义了如下的 http 配置项结构,则回调用http 配置项,并对该http 配置项进行解析。此时,解析的是http block 块设置。

    static ngx_command_t  ngx_http_commands[] = {
    
        { ngx_string("http"),
          NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
          ngx_http_block,
          0,
          0,
          NULL },
    
          ngx_null_command
    };
    
    ログイン後にコピー

            http 是作为一个 core 模块被 nginx 通用解析过程解析的,其核心就是http{} 块指令回调,它完成了http 解析的整个功能,从初始化到计算配置结果。http{} 块指令的流程是:

    • 创建并初始化上下文结构;
    • 调用通用模块配置解析流程解析;
    • 根据解析结果进行配置项合并处理;

    创建并初始化上下文结构

      当 Nginx 检查到 http{…} 配置项时,HTTP 配置模型就会启动,则会建立一个ngx_http_conf_ctx_t 结构,该结构定义在文件中:src/http/ngx_http_config.h

    typedef struct{
      /*  指针数组,数组中的每个元素指向所有 HTTP 模块 create_main_conf 方法产生的结构体 */
       void **main_conf;
       /*  指针数组,数组中的每个元素指向所有 HTTP 模块 create_srv_conf 方法产生的结构体 */
       void **srv_conf;
       /*  指针数组,数组中的每个元素指向所有 HTTP 模块 create_loc_conf 方法产生的结构体 */
       void **loc_conf;
    }ngx_http_conf_ctx_t;
    
    ログイン後にコピー

      此时,HTTP 框架为所有 HTTP 模块建立 3 个数组,分别存放所有 HTTP 模块的create_main_confcreate_srv_confcreate_loc_conf 方法返回的地址指针。ngx_http_conf_ctx_t 结构的三个成员分别指向这 3 个数组。例如下面的例子是设置 create_main_confcreate_srv_conf 、create_loc_conf  返回的地址。

    ngx_http_conf_ctx *ctx;
    /* HTTP 框架生成 1 个 ngx_http_conf_ctx_t 结构变量 */
    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
    
    *(ngx_http_conf_ctx_t **) conf = ctx;
    
    ...
    /* 分别生成 3 个数组存储所有的 HTTP 模块的 create_main_conf、create_srv_conf、create_loc_conf 方法返回的地址 */
    ctx->main_conf = ngx_pcalloc(cf->pool,
                                 sizeof(void *) * ngx_http_max_module);
    
    ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
    
    ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
    
    /* 遍历所有 HTTP 模块 */
    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }
    
        module = ngx_modules[m]->ctx;
        mi = ngx_modules[m]->ctx_index;
    
        /* 若实现了create_main_conf 方法,则调用该方法,并把返回的地址存储到 main_conf 中 */
        if (module->create_main_conf) {
            ctx->main_conf[mi] = module->create_main_conf(cf);
        }
        /* 若实现了create_srv_conf 方法,则调用该方法,并把返回的地址存储到 srv_conf 中 */
        if (module->create_srv_conf) {
            ctx->srv_conf[mi] = module->create_srv_conf(cf);
        }
        /* 若实现了create_loc_conf 方法,则调用该方法,并把返回的地址存储到 loc_conf 中 */
        if (module->create_loc_conf) {
            ctx->loc_conf[mi] = module->create_loc_conf(cf);
        }
    }
    
    pcf = *cf;
    cf->ctx = ctx;
    
    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }
    
        module = ngx_modules[m]->ctx;
    
        if (module->preconfiguration) {
            if (module->preconfiguration(cf) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }
    }
    
    ログイン後にコピー

    调用通用模块配置解析流程解析

            从源码 src/http/ngx_http.c 中可以看到,http 块的配置解析是调用通用模块的配置解析函数,其实现如下:

        /* 调用通用模块配置解析 */
        /* parse inside the http{} block */
    
        cf->module_type = NGX_HTTP_MODULE;
        cf->cmd_type = NGX_HTTP_MAIN_CONF;
        rv = ngx_conf_parse(cf, NULL);
    
        if (rv != NGX_CONF_OK) {
            goto failed;
        }
    
    ログイン後にコピー

    根据解析结果进行配置项合并处理

        /* 根据解析结构进行合并处理 */
        /*
         * init http{} main_conf's, merge the server{}s' srv_conf's
         * and its location{}s' loc_conf's
         */
    
        cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
        cscfp = cmcf->servers.elts;
    
        for (m = 0; ngx_modules[m]; m++) {
            if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
                continue;
            }
    
            module = ngx_modules[m]->ctx;
            mi = ngx_modules[m]->ctx_index;
    
            /* init http{} main_conf's */
    
            if (module->init_main_conf) {
                rv = module->init_main_conf(cf, ctx->main_conf[mi]);
                if (rv != NGX_CONF_OK) {
                    goto failed;
                }
            }
    
            rv = ngx_http_merge_servers(cf, cmcf, module, mi);
            if (rv != NGX_CONF_OK) {
                goto failed;
            }
        }
    
    
        /* create location trees */
    
        for (s = 0; s < cmcf->servers.nelts; s++) {
    
            clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
    
            if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
    
            if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }
    
    
        if (ngx_http_init_phases(cf, cmcf) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    
        if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    
    
        for (m = 0; ngx_modules[m]; m++) {
            if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
                continue;
            }
    
            module = ngx_modules[m]->ctx;
    
            if (module->postconfiguration) {
                if (module->postconfiguration(cf) != NGX_OK) {
                    return NGX_CONF_ERROR;
                }
            }
        }
    
        if (ngx_http_variables_init_vars(cf) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    
        /*
         * http{}'s cf->ctx was needed while the configuration merging
         * and in postconfiguration process
         */
    
        *cf = pcf;
    
    
        if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    
    
        /* optimize the lists of ports, addresses and server names */
    
        if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    
        return NGX_CONF_OK;
    
    failed:
    
        *cf = pcf;
    
        return rv;
    
    ログイン後にコピー

    HTTP 配置解析流程

            从上面的分析中可以总结出 HTTP 配置解析的流程如下:

    • Nginx 进程进入主循环,在主循环中调用配置解析器解析配置文件nginx.conf;
    • 在配置文件中遇到 http{} 块配置,则 HTTP 框架开始启动,其由函数 ngx_http_block() 实现;
    • HTTP 框架初始化所有 HTTP 模块的序列号,并创建 3 个类型为 ngx_http_conf_ctx_t 结构的数组用于存储所有HTTP 模块的create_main_confcreate_srv_confcreate_loc_conf方法返回的指针地址;
    • 调用每个 HTTP 模块的 preconfiguration 方法;
    • HTTP 框架调用函数 ngx_conf_parse() 开始循环解析配置文件 nginx.conf 中的http{}块里面的所有配置项;
    • HTTP 框架处理完毕 http{} 配置项,根据解析配置项的结果,必要时进行配置项合并处理;
    • 继续处理其他 http{} 块之外的配置项,直到配置文件解析器处理完所有配置项后通知Nginx 主循环配置项解析完毕。此时,Nginx 才会启动Web 服务器;

    合并配置项

            HTTP 框架解析完毕 http{} 块配置项时,会根据解析的结果进行合并配置项操作,即合并 http{}server{}location{} 不同块下各HTTP 模块生成的存放配置项的结构体。其合并过程如下所示:

    • HTTP 模块实现了 merge_srv_conf 方法,则将 http{} 块下create_srv_conf 生成的结构体与遍历每一个 server{}配置块下的结构体进行merge_srv_conf 操作;
    • HTTP 模块实现了 merge_loc_conf 方法,则将 http{} 块下create_loc_conf 生成的结构体与嵌套每一个server{} 配置块下的结构体进行merge_loc_conf 操作;
    • HTTP 模块实现了 merge_loc_conf 方法,则将server{} 块下create_loc_conf 生成的结构体与嵌套每一个location{}配置块下的结构体进行merge_loc_conf 操作;
    • HTTP 模块实现了 merge_loc_conf 方法,则将location{} 块下create_loc_conf 生成的结构体与嵌套每一个location{}配置块下的结构体进行merge_loc_conf 操作;

            以下是合并配置项操作的源码实现:

    /* 合并配置项操作 */
    static char *
    ngx_http_merge_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
        ngx_http_module_t *module, ngx_uint_t ctx_index)
    {
        char                        *rv;
        ngx_uint_t                   s;
        ngx_http_conf_ctx_t         *ctx, saved;
        ngx_http_core_loc_conf_t    *clcf;
        ngx_http_core_srv_conf_t   **cscfp;
    
        cscfp = cmcf->servers.elts;
        ctx = (ngx_http_conf_ctx_t *) cf->ctx;
        saved = *ctx;
        rv = NGX_CONF_OK;
    
        /* 遍历每一个server{}块 */
        for (s = 0; s < cmcf->servers.nelts; s++) {
    
            /* merge the server{}s' srv_conf's */
    
            ctx->srv_conf = cscfp[s]->ctx->srv_conf;
    
            /*
             * 若定义了merge_srv_conf 方法;
             * 则进行http{}块下create_srv_conf 生成的结构体与遍历server{}块配置项生成的结构体进行merge_srv_conf操作;
             */
            if (module->merge_srv_conf) {
                rv = module->merge_srv_conf(cf, saved.srv_conf[ctx_index],
                                            cscfp[s]->ctx->srv_conf[ctx_index]);
                if (rv != NGX_CONF_OK) {
                    goto failed;
                }
            }
    
            /*
             * 若定义了merge_loc_conf 方法;
             * 则进行http{}块下create_loc_conf 生成的结构体与嵌套server{}块配置项生成的结构体进行merge_loc_conf操作;
             */
            if (module->merge_loc_conf) {
    
                /* merge the server{}'s loc_conf */
    
                ctx->loc_conf = cscfp[s]->ctx->loc_conf;
    
                rv = module->merge_loc_conf(cf, saved.loc_conf[ctx_index],
                                            cscfp[s]->ctx->loc_conf[ctx_index]);
                if (rv != NGX_CONF_OK) {
                    goto failed;
                }
    
                /* merge the locations{}' loc_conf's */
    
                /*
                 * 若定义了merge_loc_conf 方法;
                 * 则进行server{}块下create_loc_conf 生成的结构体与嵌套location{}块配置项生成的结构体进行merge_loc_conf操作;
                 */
                clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
    
                rv = ngx_http_merge_locations(cf, clcf->locations,
                                              cscfp[s]->ctx->loc_conf,
                                              module, ctx_index);
                if (rv != NGX_CONF_OK) {
                    goto failed;
                }
            }
        }
    
    failed:
    
        *ctx = saved;
    
        return rv;
    }
    
    
    static char *
    ngx_http_merge_locations(ngx_conf_t *cf, ngx_queue_t *locations,
        void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index)
    {
        char                       *rv;
        ngx_queue_t                *q;
        ngx_http_conf_ctx_t        *ctx, saved;
        ngx_http_core_loc_conf_t   *clcf;
        ngx_http_location_queue_t  *lq;
    
        if (locations == NULL) {
            return NGX_CONF_OK;
        }
    
        ctx = (ngx_http_conf_ctx_t *) cf->ctx;
        saved = *ctx;
    
        /*
         * 若定义了merge_loc_conf 方法;
         * 则进行location{}块下create_loc_conf 生成的结构体与嵌套location{}块配置项生成的结构体进行merge_loc_conf操作;
         */
        for (q = ngx_queue_head(locations);
             q != ngx_queue_sentinel(locations);
             q = ngx_queue_next(q))
        {
            lq = (ngx_http_location_queue_t *) q;
    
            clcf = lq->exact ? lq->exact : lq->inclusive;
            ctx->loc_conf = clcf->loc_conf;
    
            rv = module->merge_loc_conf(cf, loc_conf[ctx_index],
                                        clcf->loc_conf[ctx_index]);
            if (rv != NGX_CONF_OK) {
                return rv;
            }
    
            /*
             * 递归调用该函数;
             * 因为location{}继续内嵌location{}
             */
            rv = ngx_http_merge_locations(cf, clcf->locations, clcf->loc_conf,
                                          module, ctx_index);
            if (rv != NGX_CONF_OK) {
                return rv;
            }
        }
    
        *ctx = saved;
    
        return NGX_CONF_OK;
    }
    
    
    ログイン後にコピー

    处理自定义的配置

            在文章中 《Nginx 模块开发》,我们给出了“Hello World” 的开发例子,在这个开发例子中,我们定义了自己的配置项,配置项名称的结构体定义如下:

    typedef struct  
    {  
            ngx_str_t hello_string;  
            ngx_int_t hello_counter;  
    }ngx_http_hello_loc_conf_t;  
    
    ログイン後にコピー

            为了处理我们定义的配置项结构,因此,我们把 ngx_command_t 结构体定义如下:

    static ngx_command_t ngx_http_hello_commands[] = {  
       {  
                    ngx_string("hello_string"),  
                    NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1,  
                    ngx_http_hello_string,  
                    NGX_HTTP_LOC_CONF_OFFSET,  
                    offsetof(ngx_http_hello_loc_conf_t, hello_string),  
                    NULL },  
      
            {  
                    ngx_string("hello_counter"),  
                    NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,  
                    ngx_http_hello_counter,  
                    NGX_HTTP_LOC_CONF_OFFSET,  
                    offsetof(ngx_http_hello_loc_conf_t, hello_counter),  
                    NULL },  
      
            ngx_null_command  
    };  
    
    ログイン後にコピー

            处理方法 ngx_http_hello_stringngx_http_hello_counter 定义如下:

    static char *  
    ngx_http_hello_string(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)  
    {  
      
            ngx_http_hello_loc_conf_t* local_conf;  
      
      
            local_conf = conf;  
            char* rv = ngx_conf_set_str_slot(cf, cmd, conf);  
      
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "hello_string:%s", local_conf->hello_string.data);  
      
            return rv;  
    }  
      
      
    static char *ngx_http_hello_counter(ngx_conf_t *cf, ngx_command_t *cmd,  
            void *conf)  
    {  
            ngx_http_hello_loc_conf_t* local_conf;  
      
            local_conf = conf;  
      
            char* rv = NULL;  
      
            rv = ngx_conf_set_flag_slot(cf, cmd, conf);  
      
      
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "hello_counter:%d", local_conf->hello_counter);  
            return rv;  
    }  
    
    ログイン後にコピー

    参考资料:

    《深入理解 Nginx 》

    《nginx 启动阶段》

    《Nginx高性能Web服务器详解》

    以上就介绍了Nginx 配置解析,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

  • 関連ラベル:
    ソース:php.cn
    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
    人気のチュートリアル
    詳細>
    最新のダウンロード
    詳細>
    ウェブエフェクト
    公式サイト
    サイト素材
    フロントエンドテンプレート
    私たちについて 免責事項 Sitemap
    PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!