>  기사  >  백엔드 개발  >  Nginx 구성 분석

Nginx 구성 분석

WBOY
WBOY원래의
2016-08-08 09:31:25938검색

개요

지난 글에서 " Nginx 시작 초기화 프로세스'에서는 Nginx의 시작 프로세스를 간략하게 소개하고 시작 프로세스의 소스 코드를 분석합니다. 시작 프로세스에는 ngx_init_cycle() 함수를 호출하는 매우 중요한 단계가 있습니다. 이 함수의 호출은 구성 구문 분석을 위한 인터페이스를 제공합니다. 구성 구문 분석 인터페이스는 대략 두 단계, 즉 데이터 준비 단계와 구성 구문 분석 단계로 나눌 수 있습니다.

데이터 준비 단계에는 다음이 포함됩니다.

  • 메모리 준비; 🎜>오류 로그 준비;
  • 필요한 데이터 구조 준비; ngx_conf_t
  • 구조
  • 이 구조는
Nginx

에서 구문 분석 시 각 지시어의 속성을 설명하는 데 사용됩니다. 구성 파일은

Nginx
    /* 配置文件解析 */  
    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;  
    }  
파일에 정의된 데이터 구조에서도 매우 중요합니다.

src/core/ngx_conf_file.h

설정 파일 정보

conf_file 🎜>conf_fileNginx 설정 파일의 관련 정보를 저장하는 곳입니다.
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;/* 自定义处理函数需要的相关配置 */
};

Configuration contextctx

Nginx의 구성 파일은 다음과 같습니다. 구성 단위로 나누어져 있으며, 일반적인 구성에는 http 블록, 서버

블록,
typedef struct {
    ngx_file_t            file;     /* 文件的属性 */
    ngx_buf_t            *buffer;   /* 文件的内容 */
    ngx_uint_t            line;     /* 文件的行数 */
} ngx_conf_file_t;
위치

블록, upsteam 블록 및

메일 차단하세요. 이러한 각 구성 블록은 범위를 나타냅니다. 상위 수준 구성 블록의 범위에는 여러 하위 수준 구성 블록의 범위가 포함되는데, 이는 범위 중첩 현상입니다. 이러한 방식으로 구성 파일의 많은 지시문이 동시에 여러 범위에 포함됩니다. 예를 들어,

http 블록의 명령은 http 블록, 서버 블록 및 위치의 세 가지 범위에 동시에 있을 수 있습니다. 차단하다. Nginx 프로그램이 구성 파일을 구문 분석할 때 각 명령어는 자신이 속한 범위를 기록해야 하며 구성 파일 컨텍스트 ctx 변수는 해당 파일을 저장하는 데 사용됩니다. 현재 지시문이 속한 범위입니다. Nginx 구성 파일의 다양한 구성 블록 중 http 블록에는 저장 구조 측면에서 더 복잡한 하위 구성 블록이 포함될 수 있습니다. 명령어 유형유형

               Nginx 프로그램의 다양한 명령어 유형은 매크로 형식의 다양한 소스 도크 파일에 정의됩니다. >core 모듈 유형은 src/core/ngx_conf_file.h 파일에 정의되어 있습니다. 이는

core

유형 모듈에서 지원하는 명령어 유형입니다. NGX_DIRECT_CONF 클래스 명령어는

Nginx

프로그램이 구성 파싱 함수에 들어가기 전에 초기화되었기 때문에 구성 파싱 함수에 들어간 후 직접 파싱하여 실제 데이터 구조에 저장할 수 있습니다. 구성 파일의 구조에서 일반적으로 구성 블록 외부에 있고 구성 파일의 전역 블록 부분에 있는 명령을 참조합니다. NGX_MAIN_CONF 클래스 지침에는 event, http,

mail
#define NGX_DIRECT_CONF            0x00010000  
#define NGX_MAIN_CONF              0x01000000  
#define NGX_ANY_CONF               0x0F000000 
, upstream 및 구성 블록을 형성할 수 있는 기타 지침이 포함됩니다. 자체 초기화 기능이 없습니다. Nginx 프로그램이 구성 파일을 구문 분석할 때 NGX_MAIN_CONF 클래스 명령어를 발견하면 다음 수준 명령어의 구문 분석으로 전환됩니다. 이벤트 유형 모듈에서 지원하는 명령어 유형은 다음과 같습니다. 다음은 파일에 정의된 http 유형 모듈에서 지원하는 명령 유형입니다. src/http/ngx_http_config.h일반 모듈 구성 분석

구성 분석 모듈은 src/core/ngx_conf_file.c에 구현되었습니다. 모듈에서 제공하는 인터페이스 기능은 주로

ngx_conf_parse
#define NGX_EVENT_CONF            0x02000000 
입니다. 또한 이 모듈은 명령줄에서 전달된 구성을 구문 분석하는 데 사용되는 또 다른 별도의 인터페이스

ngx_conf_param을 제공합니다. 이 인터페이스는 ngx_conf_parse에 대한 래퍼이기도 합니다. 먼저, 다음과 같이 정의되어 있는 구성 파싱 함수 ngx_conf_parse

를 살펴보자.
#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  

구성 파싱 함수의 소스코드를 보면 알 수 있듯이 이 함수는 다음과 같이 나누어진다. 두 단계: 구문 분석 및 명령어 구문 분석. 구문 분석은

ngx_conf_read_token()

함수로 완료됩니다. 명령 구문 분석에는 두 가지 방법이 있습니다. 하나는 Nginx의 내장 명령 구문 분석 메커니즘이고, 다른 하나는 사용자 정의 명령 구문 분석 메커니즘입니다. 사용자 정의 명령 구문 분석 소스 코드는 다음과 같습니다. 그리고 Nginx에 내장된 구문 분석 메커니즘은 ngx_conf_handler() 함수로 구현됩니다. 그 정의는 다음과 같습니다. HTTP

모듈 구성 분석
/*
 * 函数功能:配置文件解析;
 * 支持三种不同的解析类型:
 * 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;
}
여기서 주요 구조는 ngx_command_t
        /* 自定义指令处理函数 */
        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;
        }
이 구조를 "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教程有兴趣的朋友有所帮助。

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.