Initialisierung des HTTP-Moduls in Nginx
Übersicht
Im vorherigen Artikel „ „Nginx Konfigurationsanalyse“ erläutert kurz die Konfigurationselementanalyse des allgemeinen Moduls und erläutert grob den Konfigurationselementanalyseprozess des HTTP-Moduls. Dieser Artikel bietet eine detailliertere Analyse. HTTP Initialisierungsprozess des Moduls. HTTP Der Modulinitialisierungsprozess umfasst hauptsächlich: Initialisierung der Kontextstruktur, Analyse von Konfigurationselementen, Zusammenführung von Konfigurationselementen und Server bezogene Porteinstellungen.
HTTP Modulschnittstelle
ngx_http_module_t Struktur
In Nginx, Strukturngx_module_t ist die grundlegendste Schnittstelle des Nginx-Moduls. Für jeden Modultyp gibt es eine spezifische Struktur, die die gemeinsame Schnittstelle dieses Modultyps beschreibt. Definiert in Nginx HTTP Die allgemeine Schnittstelle des Moduls ngx_http_module_t Struktur, die in der Datei src/http/ngx_http_config.h definiert ist: Wir platzieren sie direkt unter der http{ Die Konfigurationselemente der Blöcke }, server{} und location{} heißen jeweils main, srv und loc Level-Konfigurationselement.
/* 所有HTTP模块的通用接口结构ngx_http_module_t */ typedef struct { /* 在解析http{}块内的配置项前回调 */ ngx_int_t (*preconfiguration)(ngx_conf_t *cf); /* 在解析http{}块内的配置项后回调 */ ngx_int_t (*postconfiguration)(ngx_conf_t *cf); /* * 创建用于存储HTTP全局配置项的结构体; * 该结构体中的成员将保存直属于http{}块的配置项参数; * 该方法在解析main配置项前调用; */ void *(*create_main_conf)(ngx_conf_t *cf); /* 解析完main配置项后回调 */ char *(*init_main_conf)(ngx_conf_t *cf, void *conf); /* * 创建用于存储可同时出现在main、srv级别配置项的结构体; * 该结构体中的成员与server配置是相关联的; */ void *(*create_srv_conf)(ngx_conf_t *cf); /* * 由create_srv_conf产生的结构体所要解析的配置项, * 可能同时出现在main、srv级别中, * merge_srv_conf 方法可以将出现在main级别中的配置项值合并到srv级别的配置项中; */ char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); /* * 创建用于存储同时出现在main、srv、loc级别配置项的结构体, * 该结构体成员与location配置相关联; */ void *(*create_loc_conf)(ngx_conf_t *cf); /* * 由create_loc_conf 产生的结构体所要解析的配置项, * 可能同时出现在main、srv、loc级别的配置项中, * merge_loc_conf 方法将出现在main、srv级别的配置项值合并到loc级别的配置项中; */ char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf); } ngx_http_module_t;
ngx_http_conf_ctx_t Struktur
Im HTTP-Modul ist die Struktur der Management-HTTP-Modulkonfigurationselemente wie folgt dargestellt durch ngx_http_conf_ctx_t Diese Struktur hat drei Mitglieder, die jeweils auf drei Zeiger-Arrays verweisen. Das Zeiger-Array besteht aus den entsprechenden HTTP-Modulen create_main_conf. create_srv_conf , ein Array bestehend aus Strukturzeigern, die mit der Methode create_loc_conf erstellt wurden. ngx_http_conf_ctx_t Die Struktur ist in der Datei definiert src/http/ngx_http_config.h In:
/* HTTP框架的上下文结构体ngx_http_conf_ctx_t */ typedef struct { /* * 指向一个指针数组; * 数组中的每个成员都是由所有HTTP模块create_main_conf方法创建的存放全局配置项的结构体, * 它们存放着解析直属于http{}块内main级别的配置项参数; */ void **main_conf; /* * 指向一个指针数组; * 数组中的每个成员都是由所有HTTP模块create_srv_conf方法创建的与server相关的配置项结构体, * 它们存放着main级别,或srv级别的配置项参数; * 这与当前的ngx_http_conf_ctx_t是在解析http{}或server{}块时创建有关; */ void **srv_conf; /* * 指向一个指针数组; * 数组中的每个成员都是由所有HTTP模块create_loc_conf方法创建的与location有关的配置项结构体, * 它们存放着main级别、srv级别、loc级别的配置项参数; * 这样当前ngx_http_conf_ctx_t是在解析http{}、server{}或location{}块时创建有关; */ void **loc_conf; } ngx_http_conf_ctx_t;
ngx_http_module Kernmodul
ngx_http_module Kernmoduldefinition
ngx_http_module ist das Kernmodul des HTTP-Moduls. Die Funktion dieses Moduls besteht darin, einen neuen HTTP-Modultyp zu definieren und jeden HTTP Modul definiert eine gemeinsame Schnittstelle Die Struktur ngx_http_module_t verwaltet die vom Modul HTTP generierte Konfigurationselementstruktur und analysiert die Konfigurationselemente der Klasse HTTP. Dieses Modul ist in der Datei definiert src/http/ngx_http.c In:
/* 定义http核心模块 */ ngx_module_t ngx_http_module = { NGX_MODULE_V1, &ngx_http_module_ctx, /* module context */ ngx_http_commands, /* module directives */ NGX_CORE_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ NULL, /* exit master */ NGX_MODULE_V1_PADDING };
ngx_http_module Als Kernmodul muss die allgemeine Schnittstellenkontextstruktur des Kernmoduls definiert werden in der Datei src/http/ngx_http.c: Nur der Name des http-Moduls ist im ngx_http_module-Kernmodul definiert.
/* 定义核心模块的通用接口上下文结构 */ static ngx_core_module_t ngx_http_module_ctx = { ngx_string("http"), NULL, NULL };
ngx_http_module definiert http{} blockiert das Array von Konfigurationselementen, an denen der Block interessiert ist. Das Konfigurationselement-Array ist in der Datei definiert src/http/ngx_http.c:
/* 定义http模块感兴趣的配置项,即配置项指令数组 */ 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 };
ngx_http_module können wir erkennen, dass dieses Modul nur eine Initialisierungsverarbeitungsmethode hat ngx_http_block , die Verarbeitungsmethode ist HTTP Initialisierungsfunktion des Moduls.
ngx_http_module Initialisierung des Kernmoduls
Aus der obigen Definition des Modulsngx_http_module ist bereits bekannt, dass der Initialisierungsprozess des HTTP erfolgt Das Modul wird durch die Funktion ngx_http_block implementiert. Zuerst wird die Gesamtanalyse der Funktion durchgeführt und dann wird die spezifische Analyse der Funktion durchgeführt. Diese Funktion ist in der Datei src/http/ngx_http.c definiert:
/* HTTP框架初始化 */ static char * ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; ngx_uint_t mi, m, s; ngx_conf_t pcf; ngx_http_module_t *module; ngx_http_conf_ctx_t *ctx; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t **cscfp; ngx_http_core_main_conf_t *cmcf; /* the main http context */ /* 分配HTTP框架的上下文结构ngx_http_conf_ctx_t 空间 */ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); if (ctx == NULL) { return NGX_CONF_ERROR; } /* * conf 是结构体ngx_cycle_t 成员conf_ctx数组中的元素, * 该元素conf指向ngx_http_module模块所对应的配置项结构信息; */ *(ngx_http_conf_ctx_t **) conf = ctx; /* count the number of the http modules and set up their indices */ /* 初始化所有HTTP模块的ctx_index序号 */ ngx_http_max_module = 0; for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_HTTP_MODULE) { continue; } ngx_modules[m]->ctx_index = ngx_http_max_module++; } /* * 分配存储HTTP模块main级别下的main_conf配置项的空间; */ /* the http main_conf context, it is the same in the all http contexts */ ctx->main_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); if (ctx->main_conf == NULL) { return NGX_CONF_ERROR; } /* * 分配存储HTTP模块main级别下的srv_conf配置项的空间; */ /* * the http null srv_conf context, it is used to merge * the server{}s' srv_conf's */ ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); if (ctx->srv_conf == NULL) { return NGX_CONF_ERROR; } /* * 分配存储HTTP模块main级别下的loc_conf配置项的空间; */ /* * the http null loc_conf context, it is used to merge * the server{}s' loc_conf's */ ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); if (ctx->loc_conf == NULL) { return NGX_CONF_ERROR; } /* * create the main_conf's, the null srv_conf's, and the null loc_conf's * of the all http modules */ /* * 遍历所有HTTP模块,为每个HTTP模块创建main级别的配置项结构main_conf、srv_conf、loc_conf; */ 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级别的配置项结构main_conf; */ if (module->create_main_conf) { ctx->main_conf[mi] = module->create_main_conf(cf); if (ctx->main_conf[mi] == NULL) { return NGX_CONF_ERROR; } } /* * 调用create_srv_conf创建main级别的配置项结构srv_conf; */ if (module->create_srv_conf) { ctx->srv_conf[mi] = module->create_srv_conf(cf); if (ctx->srv_conf[mi] == NULL) { return NGX_CONF_ERROR; } } /* * 调用create_loc_conf创建main级别的配置项结构loc_conf; */ if (module->create_loc_conf) { ctx->loc_conf[mi] = module->create_loc_conf(cf); if (ctx->loc_conf[mi] == NULL) { return NGX_CONF_ERROR; } } } /* * 保存待解析配置项结构cf的副本为pcf,待解析完毕后恢复cf; * 这里备份是由于配置指令解析函数ngx_conf_parse递归调用,因此为了不影响外层的调用环境; */ pcf = *cf; /* * 把HTTP模块解析指令的上下文参数保存到配置项结构ngx_http_conf_ctx_t ctx中; */ cf->ctx = ctx;/* 值-结果 模式 */ /* 遍历所有HTTP模块,并调用每个模块的preconfiguration回调函数 */ 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; } } } /* * 调用模块通用配置项解析函数ngx_conf_parse解析http{}块内的指令; */ /* parse inside the http{} block */ cf->module_type = NGX_HTTP_MODULE;/* 模块类型为HTTP模块 */ cf->cmd_type = NGX_HTTP_MAIN_CONF;/* 指令类型为HTTP模块的main级别指令 */ /* * 开始解析http{}块内的指令; * 这里必须注意的是:http{}块内可能会包含server{}块, * 而server{}可能会包含location{}块,location{}块会嵌套location{}块; * 还需注意的是http{}块内可能有多个server{}块, * location{}块也可能有多个location{}块; * 因此,配置项解析函数ngx_conf_parse是被递归调用的;*/ rv = ngx_conf_parse(cf, NULL); if (rv != NGX_CONF_OK) { goto failed; } /* * 解析完成http{}块内的所有指令后(包括server{}、location{}块的解析), * 进行下面的程序 */ /* * init http{} main_conf's, merge the server{}s' srv_conf's * and its location{}s' loc_conf's */ /* 获取ngx_http_core_module模块的main_conf配置项结构 */ cmcf = ctx->main_conf[ngx_http_core_module.ctx_index]; /* 获取所有srv_conf配置项结构 */ cscfp = cmcf->servers.elts; /* * 遍历所有HTTP模块,并初始化每个HTTP模块的main_conf结构, * 同时合并srv_conf 结构(当然srv_conf结构里面包含loc_conf结构,所有也合并loc_conf结构); */ for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_HTTP_MODULE) { continue; } /* * ngx_modules[m]是一个ngx_module_t模块结构体, * 它的ctx成员相对于HTTP模块来说是ngx_http_module_t接口; */ module = ngx_modules[m]->ctx; /* 获取当前HTTP模块在HTTP模块类的序号 */ mi = ngx_modules[m]->ctx_index; /* 初始化HTTP模块的main_conf结构 */ /* 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; } } /* 合并当前HTTP模块不同级别的配置项结构 */ rv = ngx_http_merge_servers(cf, cmcf, module, mi); if (rv != NGX_CONF_OK) { goto failed; } } /* 以下是监听端口管理的内容 */ /* 静态二叉查找树来保存location配置 */ /* create location trees */ /* 遍历http{}块下的所有server{}块 */ for (s = 0; s < cmcf->servers.nelts; s++) { /* 获取server{}块下location{}块所对应的ngx_http_core_loc_conf_t loc_conf结构体 */ clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index]; /* * 将ngx_http_core_loc_conf_t 组成的双向链表按照location匹配字符串进行排序; * 注意:location{}块可能嵌套location{}块,所以该函数是递归调用; */ if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) { return NGX_CONF_ERROR; } /* * 按照已排序的location{}的双向链表构建静态的二叉查找树, * 该方法也是递归调用; */ if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) { return NGX_CONF_ERROR; } } /* 初始化可添加自定义处理方法的7个HTTP阶段的动态数组 */ if (ngx_http_init_phases(cf, cmcf) != NGX_OK) { return NGX_CONF_ERROR; } /* 将HTTP请求的头部header初始化成hash结构 */ if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) { return NGX_CONF_ERROR; } /* 调用所有HTTP模块的postconfiguration方法 */ 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; /* 初始化phase_engine_handlers数组 */ if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) { return NGX_CONF_ERROR; } /* optimize the lists of ports, addresses and server names */ /* 设置server与监听端口的关系,并设置新连接事件的处理方法 */ 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 Modul ist wie folgt:
- Nginx 进程进入主循环,在主循环中调用配置解析器解析配置文件nginx.conf;
- 在配置文件中遇到 http{} 块配置,则 HTTP 框架开始初始化并启动,其由函数 ngx_http_block() 实现;
- HTTP 框架初始化所有 HTTP 模块的序列号,并创建 3 个类型为 ngx_http_conf_ctx_t 结构的数组用于存储所有HTTP 模块的create_main_conf、create_srv_conf、create_loc_conf方法返回的指针地址;
- 调用每个 HTTP 模块的 preconfiguration 方法;
- HTTP 框架调用函数 ngx_conf_parse() 开始循环解析配置文件 nginx.conf 中的http{}块里面的所有配置项,http{} 块内可嵌套多个server{} 块,而 server{} 块可嵌套多个 location{},location{} 依旧可以嵌套location{},因此配置项解析函数是递归调用;
- HTTP 框架处理完毕 http{} 配置项,根据解析配置项的结果,必要时调用ngx_http_merge_servers 方法进行配置项合并处理,即合并main、srv、loc 级别下server、location 相关的配置项;
- 初始化可添加处理方法的 HTTP 阶段的动态数组;
- 调用所有 HTTP 模块的 postconfiguration 方法使 HTTP 模块可以处理HTTP 阶段,即将 HTTP 模块的 ngx_http_handler_pt 处理方法添加到HTTP 阶段中;
- 根据 HTTP 模块处理 HTTP 阶段的方法构造 phase_engine_handlers 数组;
- 构造 server 相关的监听端口,并设置新连接事件的回调方法为ngx_http_init_connection ;
- 继续处理其他 http{} 块之外的配置项,直到配置文件解析器处理完所有配置项后通知Nginx 主循环配置项解析完毕。此时,Nginx 才会启动Web 服务器;
ngx_http_core_module 模块
ngx_http_core_main_conf_t 结构体
在初始化 HTTP 模块的过程中,会调用配置项解析函数 ngx_conf_parse 解析 http{} 块内的配置项,当遇到server{} 块、 location{} 块配置项时,此时会调用配置项解析函数解析 server{} 和 location{} 块,在解析这两个配置块的过程中依旧会创建属于该块的配置项结构srv_conf、loc_conf,因此就会导致与http{} 块所创建的配置项结构体重复,这时候就需要对这些配置项进行管理与合并。首先先看下结构体ngx_http_core_main_conf_t,ngx_http_core_main_conf_t 是ngx_http_core_module 的 main_conf,存储了 http{} 层的配置参数。该结构体定义在文件src/http/ngx_http_core_module.h中:
/* ngx_http_core_main_conf_t 结构体 */ typedef struct { /* 指针数组,每个指针指向表示server{}块的ngx_http_core_srv_conf_t结构体地址 */ ngx_array_t servers; /* ngx_http_core_srv_conf_t */ /* 各HTTP阶段处理方法构成的phases数组构建的阶段索引 */ ngx_http_phase_engine_t phase_engine; ngx_hash_t headers_in_hash; ngx_hash_t variables_hash; ngx_array_t variables; /* ngx_http_variable_t */ ngx_uint_t ncaptures; /* 配置项中散列桶bucket最大数量 */ ngx_uint_t server_names_hash_max_size; /* 配置项中每个散列桶bucket占用内存的最大值 */ ngx_uint_t server_names_hash_bucket_size; ngx_uint_t variables_hash_max_size; ngx_uint_t variables_hash_bucket_size; ngx_hash_keys_arrays_t *variables_keys; /* 存放http{}配置块下监听的所有ngx_http_conf_port_t 端口*/ ngx_array_t *ports; ngx_uint_t try_files; /* unsigned try_files:1 */ /* * 在HTTP模块初始化时,使各HTTP模块在HTTP阶段添加处理方法, * 数组中每一个成员ngx_http_phase_t结构对应一个HTTP阶段; */ ngx_http_phase_t phases[NGX_HTTP_LOG_PHASE + 1]; } ngx_http_core_main_conf_t;
ngx_http_core_srv_conf_t 结构体
结构体 ngx_http_core_srv_conf_t,ngx_http_core_srv_conf_t 是ngx_http_core_module 的 srv_conf,存储了 server{} 层的配置参数。该结构体定义在文件src/http/ngx_http_core_module.h中:
/* ngx_http_core_srv_conf_t结构体 */ typedef struct { /* array of the ngx_http_server_name_t, "server_name" directive */ ngx_array_t server_names; /* server ctx */ /* 指向当前server{}块所属的ngx_http_conf_ctx_t结构体 */ ngx_http_conf_ctx_t *ctx; /* 当前server{}块的虚拟主机名 */ ngx_str_t server_name; size_t connection_pool_size; size_t request_pool_size; size_t client_header_buffer_size; ngx_bufs_t large_client_header_buffers; ngx_msec_t client_header_timeout; ngx_flag_t ignore_invalid_headers; ngx_flag_t merge_slashes; ngx_flag_t underscores_in_headers; unsigned listen:1; #if (NGX_PCRE) unsigned captures:1; #endif ngx_http_core_loc_conf_t **named_locations; } ngx_http_core_srv_conf_t;
ngx_http_core_loc_conf_t 结构体
结构体 ngx_http_core_loc_conf_t,ngx_http_core_loc_conf_t 是ngx_http_core_module 的 loc_conf,存储了 location{} 层的配置参数。该结构体定义在文件src/http/ngx_http_core_module.h中:
struct ngx_http_core_loc_conf_s { /* location名称,即nginx.conf配置文件中location后面的表达式 */ ngx_str_t name; /* location name */ #if (NGX_PCRE) ngx_http_regex_t *regex; #endif unsigned noname:1; /* "if () {}" block or limit_except */ unsigned lmt_excpt:1; unsigned named:1; unsigned exact_match:1; unsigned noregex:1; unsigned auto_redirect:1; #if (NGX_HTTP_GZIP) unsigned gzip_disable_msie6:2; #if (NGX_HTTP_DEGRADATION) unsigned gzip_disable_degradation:2; #endif #endif ngx_http_location_tree_node_t *static_locations; #if (NGX_PCRE) ngx_http_core_loc_conf_t **regex_locations; #endif /* 指向所属location{}块内ngx_http_conf_ctx_t 结构体中的loc_conf指针数组 */ /* pointer to the modules' loc_conf */ void **loc_conf; uint32_t limit_except; void **limit_except_loc_conf; ngx_http_handler_pt handler; /* location name length for inclusive location with inherited alias */ size_t alias; ngx_str_t root; /* root, alias */ ngx_str_t post_action; ngx_array_t *root_lengths; ngx_array_t *root_values; ngx_array_t *types; ngx_hash_t types_hash; ngx_str_t default_type; off_t client_max_body_size; /* client_max_body_size */ off_t directio; /* directio */ off_t directio_alignment; /* directio_alignment */ size_t client_body_buffer_size; /* client_body_buffer_size */ size_t send_lowat; /* send_lowat */ size_t postpone_output; /* postpone_output */ size_t limit_rate; /* limit_rate */ size_t limit_rate_after; /* limit_rate_after */ size_t sendfile_max_chunk; /* sendfile_max_chunk */ size_t read_ahead; /* read_ahead */ ngx_msec_t client_body_timeout; /* client_body_timeout */ ngx_msec_t send_timeout; /* send_timeout */ ngx_msec_t keepalive_timeout; /* keepalive_timeout */ ngx_msec_t lingering_time; /* lingering_time */ ngx_msec_t lingering_timeout; /* lingering_timeout */ ngx_msec_t resolver_timeout; /* resolver_timeout */ ngx_resolver_t *resolver; /* resolver */ time_t keepalive_header; /* keepalive_timeout */ ngx_uint_t keepalive_requests; /* keepalive_requests */ ngx_uint_t keepalive_disable; /* keepalive_disable */ ngx_uint_t satisfy; /* satisfy */ ngx_uint_t lingering_close; /* lingering_close */ ngx_uint_t if_modified_since; /* if_modified_since */ ngx_uint_t max_ranges; /* max_ranges */ ngx_uint_t client_body_in_file_only; /* client_body_in_file_only */ ngx_flag_t client_body_in_single_buffer; /* client_body_in_singe_buffer */ ngx_flag_t internal; /* internal */ ngx_flag_t sendfile; /* sendfile */ #if (NGX_HAVE_FILE_AIO) ngx_flag_t aio; /* aio */ #endif ngx_flag_t tcp_nopush; /* tcp_nopush */ ngx_flag_t tcp_nodelay; /* tcp_nodelay */ ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */ ngx_flag_t server_name_in_redirect; /* server_name_in_redirect */ ngx_flag_t port_in_redirect; /* port_in_redirect */ ngx_flag_t msie_padding; /* msie_padding */ ngx_flag_t msie_refresh; /* msie_refresh */ ngx_flag_t log_not_found; /* log_not_found */ ngx_flag_t log_subrequest; /* log_subrequest */ ngx_flag_t recursive_error_pages; /* recursive_error_pages */ ngx_flag_t server_tokens; /* server_tokens */ ngx_flag_t chunked_transfer_encoding; /* chunked_transfer_encoding */ ngx_flag_t etag; /* etag */ #if (NGX_HTTP_GZIP) ngx_flag_t gzip_vary; /* gzip_vary */ ngx_uint_t gzip_http_version; /* gzip_http_version */ ngx_uint_t gzip_proxied; /* gzip_proxied */ #if (NGX_PCRE) ngx_array_t *gzip_disable; /* gzip_disable */ #endif #endif #if (NGX_HAVE_OPENAT) ngx_uint_t disable_symlinks; /* disable_symlinks */ ngx_http_complex_value_t *disable_symlinks_from; #endif ngx_array_t *error_pages; /* error_page */ ngx_http_try_file_t *try_files; /* try_files */ ngx_path_t *client_body_temp_path; /* client_body_temp_path */ ngx_open_file_cache_t *open_file_cache; time_t open_file_cache_valid; ngx_uint_t open_file_cache_min_uses; ngx_flag_t open_file_cache_errors; ngx_flag_t open_file_cache_events; ngx_log_t *error_log; ngx_uint_t types_hash_max_size; ngx_uint_t types_hash_bucket_size; /* 将同一个server{}块内多个表达location{}块的ngx_http_core_loc_conf_t 结构体以双向链表方式组织, * 该指针指向ngx_http_location_queue_t结构体 */ ngx_queue_t *locations; #if 0 ngx_http_core_loc_conf_t *prev_location; #endif }; typedef struct{ /* 作为ngx_queue_t 双向链表容器,将ngx_http_location_queue_t结构体连接起来 */ ngx_queue_t queue; /* 若location中字符串可以精确匹配(包括正则表达式), * exact将指向对应的ngx_http_core_loc_conf_t结构体,否则为NULL */ ngx_http_core_loc_conf_t *exact; /* 若location中字符串无精确匹配(包括自定义通配符), * inclusive将指向对应的ngx_http_core_loc_conf_t结构体,否则为NULL */ ngx_http_core_loc_conf_t *inclusive; /* 指向location的名称 */ ngx_str_t *name; ... }ngx_http_location_queue_t;
ngx_http_core_module 模块定义
ngx_http_core_module 模块是 HTTP 模块中的第一个模块,该模块管理 srv、loc 级别的配置项结构。该模块在文件src/http/ngx_http_core_module.c中定义:
ngx_module_t ngx_http_core_module = { NGX_MODULE_V1, &ngx_http_core_module_ctx, /* module context */ ngx_http_core_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ NULL, /* exit master */ NGX_MODULE_V1_PADDING };
在模块的定义中,其中定义了 HTTP 模块的上下文结构 ngx_http_core_module_ctx,该上下文结构体定义如下:
static ngx_http_module_t ngx_http_core_module_ctx = { ngx_http_core_preconfiguration, /* preconfiguration */ NULL, /* postconfiguration */ ngx_http_core_create_main_conf, /* create main configuration */ ngx_http_core_init_main_conf, /* init main configuration */ ngx_http_core_create_srv_conf, /* create server configuration */ ngx_http_core_merge_srv_conf, /* merge server configuration */ ngx_http_core_create_loc_conf, /* create location configuration */ ngx_http_core_merge_loc_conf /* merge location configuration */ };
由于该模块中感兴趣的配置项太多,这里只列出 server、location 配置项。定义如下:
... { ngx_string("server"), NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, ngx_http_core_server, 0, 0, NULL }, ... { ngx_string("location"), NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12, ngx_http_core_location, NGX_HTTP_SRV_CONF_OFFSET, 0, NULL }, ... ngx_null_command };
管理 HTTP 模块不同级别的配置项结构体
在 HTTP 模块的 http{} 配置项解析过程中,可能遇到多个嵌套 server{} 块以及location{},不同块之间的解析都会创建相应的结构体保存配置项参数,但是由于属于嵌套关系,所有必须管理好不同块之间的配置项结构体,方便解析完毕后合并相应的配置项,以下针对不同级别的配置项结构体进行分析。
main 级别的配置项结构体
在 ngx_http_module 模块 http{} 块配置项解析的初始化过程中由函数 ngx_http_block 实现,在实现过程中创建并初始化了HTTP 模块 main 级别的配置项 main_conf、srv_conf、loc_conf 结构体。main 级别的配置项结构体之间的关系如下图所示:
server 级别的配置项结构体
在
static char * ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) { char *rv; void *mconf; 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; /* 分配HTTP框架的上下文结构ngx_http_conf_ctx_t */ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); if (ctx == NULL) { return NGX_CONF_ERROR; } /* 其中main_conf将指向所属于http{}块下ngx_http_conf_ctx_t 结构体的main_conf指针数组 */ http_ctx = cf->ctx; ctx->main_conf = http_ctx->main_conf; /* the server{}'s srv_conf */ /* 分配存储HTTP模块srv级别下的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 */ /* 分配存储HTTP模块srv级别下的loc_conf配置项空间 */ ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); if (ctx->loc_conf == NULL) { return NGX_CONF_ERROR; } /* 遍历所有HTTP模块,为每个模块创建srv级别的配置项结构srv_conf、loc_conf */ for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_HTTP_MODULE) { continue; } module = ngx_modules[i]->ctx; /* 调用create_srv_conf创建srv级别的配置项结构srv_conf */ if (module->create_srv_conf) { mconf = module->create_srv_conf(cf); if (mconf == NULL) { return NGX_CONF_ERROR; } ctx->srv_conf[ngx_modules[i]->ctx_index] = mconf; } /* 调用create_loc_conf创建srv级别的配置项结构loc_conf */ if (module->create_loc_conf) { mconf = module->create_loc_conf(cf); if (mconf == NULL) { return NGX_CONF_ERROR; } ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf; } } /* * 将属于当前server{}块的ngx_http_core_srv_conf_t 添加到 * 结构体ngx_http_core_main_conf_t成员servers的动态数组中; */ /* 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; /* 解析当前server{}块下的全部srv级别的配置项 */ /* parse inside server{} */ pcf = *cf; cf->ctx = ctx; cf->cmd_type = NGX_HTTP_SRV_CONF; rv = ngx_conf_parse(cf, NULL); /* 设置listen监听端口 */ *cf = pcf; if (rv == NGX_CONF_OK && !cscf->listen) { ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t)); sin = &lsopt.u.sockaddr_in; 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; (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.socklen, lsopt.addr, NGX_SOCKADDR_STRLEN, 1); if (ngx_http_add_listen(cf, cscf, &lsopt) != NGX_OK) { return NGX_CONF_ERROR; } } return rv; }
srv 级别的配置项结构体之间的关系如下图所示:
location 级别的配置项结构体
在
static char * ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) { char *rv; u_char *mod; size_t len; ngx_str_t *value, *name; ngx_uint_t i; ngx_conf_t save; ngx_http_module_t *module; ngx_http_conf_ctx_t *ctx, *pctx; ngx_http_core_loc_conf_t *clcf, *pclcf; /* 分配HTTP框架的上下文结构ngx_http_conf_ctx_t */ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); if (ctx == NULL) { return NGX_CONF_ERROR; } /* * 其中main_conf、srv_conf将指向所属于server{}块下ngx_http_conf_ctx_t 结构体 * 的main_conf、srv_conf指针数组; */ pctx = cf->ctx; ctx->main_conf = pctx->main_conf; ctx->srv_conf = pctx->srv_conf; /* 分配存储HTTP模块loc级别下的loc_conf配置项空间 */ ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); if (ctx->loc_conf == NULL) { return NGX_CONF_ERROR; } /* 遍历所有HTTP模块,为每个模块创建loc级别的配置项结构体loc_conf */ for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_HTTP_MODULE) { continue; } module = ngx_modules[i]->ctx; /* 调用模块的create_loc_conf创建loc级别的配置项结构体loc_conf */ if (module->create_loc_conf) { ctx->loc_conf[ngx_modules[i]->ctx_index] = module->create_loc_conf(cf); /* 将loc_conf配置项结构体按照ctx_index顺序保存到loc_conf指针数组中 */ if (ctx->loc_conf[ngx_modules[i]->ctx_index] == NULL) { return NGX_CONF_ERROR; } } } clcf = ctx->loc_conf[ngx_http_core_module.ctx_index]; clcf->loc_conf = ctx->loc_conf; value = cf->args->elts; /* 以下是对正则表达式的处理 */ if (cf->args->nelts == 3) { len = value[1].len; mod = value[1].data; name = &value[2]; if (len == 1 && mod[0] == '=') { clcf->name = *name; clcf->exact_match = 1; } else if (len == 2 && mod[0] == '^' && mod[1] == '~') { clcf->name = *name; clcf->noregex = 1; } else if (len == 1 && mod[0] == '~') { if (ngx_http_core_regex_location(cf, clcf, name, 0) != NGX_OK) { return NGX_CONF_ERROR; } } else if (len == 2 && mod[0] == '~' && mod[1] == '*') { if (ngx_http_core_regex_location(cf, clcf, name, 1) != NGX_OK) { return NGX_CONF_ERROR; } } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid location modifier \"%V\"", &value[1]); return NGX_CONF_ERROR; } } else { name = &value[1]; if (name->data[0] == '=') { clcf->name.len = name->len - 1; clcf->name.data = name->data + 1; clcf->exact_match = 1; } else if (name->data[0] == '^' && name->data[1] == '~') { clcf->name.len = name->len - 2; clcf->name.data = name->data + 2; clcf->noregex = 1; } else if (name->data[0] == '~') { name->len--; name->data++; if (name->data[0] == '*') { name->len--; name->data++; if (ngx_http_core_regex_location(cf, clcf, name, 1) != NGX_OK) { return NGX_CONF_ERROR; } } else { if (ngx_http_core_regex_location(cf, clcf, name, 0) != NGX_OK) { return NGX_CONF_ERROR; } } } else { clcf->name = *name; if (name->data[0] == '@') { clcf->named = 1; } } } pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index]; if (pclcf->name.len) { /* nested location */ #if 0 clcf->prev_location = pclcf; #endif if (pclcf->exact_match) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "location \"%V\" cannot be inside " "the exact location \"%V\"", &clcf->name, &pclcf->name); return NGX_CONF_ERROR; } if (pclcf->named) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "location \"%V\" cannot be inside " "the named location \"%V\"", &clcf->name, &pclcf->name); return NGX_CONF_ERROR; } if (clcf->named) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "named location \"%V\" can be " "on the server level only", &clcf->name); return NGX_CONF_ERROR; } len = pclcf->name.len; #if (NGX_PCRE) if (clcf->regex == NULL && ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0) #else if (ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0) #endif { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "location \"%V\" is outside location \"%V\"", &clcf->name, &pclcf->name); return NGX_CONF_ERROR; } } /* 将ngx_http_location_queue_t添加到双向链表中 */ if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) { return NGX_CONF_ERROR; } save = *cf; cf->ctx = ctx; cf->cmd_type = NGX_HTTP_LOC_CONF; /* 解析当前location{}块下的所有loc级别配置项 */ rv = ngx_conf_parse(cf, NULL); *cf = save; return rv; }
loc 级别的配置项结构体之间的关系如下图所示:若 location 是精确匹配、正则表达式、@命名则exact 字段有效,否则就是 inclusive 字段有效,画图过程中只画出 exact 字段有效。
合并配置项
HTTP 框架解析完毕 http{} 块配置项时,会根据解析的结果进行合并配置项操作,即合并 http{}、server{}、location{} 不同级别下各 HTTP 模块生成的存放配置项的结构体。其合并过程在文件 src/http/ngx_http.c中定义,如下所示:
- 若 HTTP 模块实现了 merge_srv_conf 方法,则将 http{} 块下由 create_srv_conf 生成的 main 级别结构体与遍历每一个 server{}块下由
create_srv_conf 生成的 srv 级别的配置项结构体进行 merge_srv_conf 操作; - 若 HTTP 模块实现了 merge_loc_conf 方法,则将 http{} 块下由 create_loc_conf 生成的 main 级别的配置项结构体与嵌套在每一个server{} 块下由
create_loc_conf 生成的 srv级别的配置项结构体进行merge_loc_conf 操作; - 若 HTTP 模块实现了 merge_loc_conf 方法,由于在上一步骤已经将main、srv级别由
create_loc_conf 生成的结构体进行合并,只要把上一步骤合并的结果在 server{} 块下与嵌套每一个location{}块下由create_loc_conf 生成的配置项结构体再次进行merge_loc_conf 操作; - 若 HTTP 模块实现了 merge_loc_conf 方法,则将上一步骤的合并结果与与嵌套每一个location{}块下由
create_loc_conf 生成的的配置项结构体再次进行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; /* * ngx_http_core_main_conf_t 中的成员servers是指针数组, * servers数组中的指针指向ngx_http_core_srv_conf_t结构体; */ cscfp = cmcf->servers.elts; ctx = (ngx_http_conf_ctx_t *) cf->ctx; saved = *ctx; rv = NGX_CONF_OK; /* 遍历每一个server{}块内对应的ngx_http_core_srv_conf_t结构体 */ for (s = 0; s < cmcf->servers.nelts; s++) { /* merge the server{}s' srv_conf's */ /* srv_conf指向所有HTTP模块产生的server相关的srv级别配置项结构体 */ ctx->srv_conf = cscfp[s]->ctx->srv_conf; /* * 这里合并http{}块下main、server{}块下srv级别与server相关的配置项结构; * * 若定义了merge_srv_conf 方法; * 则将当前HTTP模块在http{}块下由create_srv_conf 生成的结构体 * 与遍历每个server{}块由create_srv_conf生成的配置项结构体进行merge_srv_conf合并操作; * saved.srv_conf[ctx_index]表示当前HTTP模块在http{}块下由create_srv_conf方法创建的结构体; * cscfp[s]->ctx->srv_conf[ctx_index]表示当前HTTP模块在server{}块下由create_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; } } /* * 这里合并http{}块下main、server{}块下srv级别与location相关的配置项结构; * * 若定义了merge_loc_conf 方法; * 则将当前HTTP模块在http{}块下由create_loc_conf 生成的结构体 * 与嵌套在server{}块内由create_loc_conf生成的配置项结构体进行merge_loc_conf合并操作; * * 其中saved.loc_conf[ctx_index]表示当前HTTP模块在http{}块下由create_loc_conf方法生成的配置项结构体; * cscfp[s]->ctx->loc_conf[ctx_index]表示当前HTTP模块在server{}块下由create_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表示ngx_http_core_module模块在server{}块下由create_loc_conf方法创建的ngx_http_core_loc_conf_t 结构体 */ 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; /* 若locations链表为空,即server{}块下没有嵌套location{}块,则立即返回 */ 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操作; */ /* 遍历locations双向链表 */ for (q = ngx_queue_head(locations); q != ngx_queue_sentinel(locations); q = ngx_queue_next(q)) { lq = (ngx_http_location_queue_t *) q; /* exact 与 inclusive 的区别在文章中已经说过 */ clcf = lq->exact ? lq->exact : lq->inclusive; /* 获取由create_loc_conf方法创建的结构体指针 */ ctx->loc_conf = clcf->loc_conf; /* 合并srv、loc级别的location相关的配置项结构 */ 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; }
HTTP 请求处理阶段
按照下列顺序将各个模块设置的phase handler依次加入cmcf->phase_engine.handlers列表,各个phase的phase handler的checker不同。checker主要用于限定某个phase的框架逻辑,包括处理返回值。 在 Nginx 定义了 11 个处理阶段,有一部分是不能添加 phase handler 方法的。在文件 src/http/ngx_http_core_module.h中定义,如下所示:
/* HTTP请求的11个处理阶段 */ typedef enum { /* 接收到完整的HTTP头部后处理的HTTP阶段,可自定义handler处理方法 */ NGX_HTTP_POST_READ_PHASE = 0, /* 将请求的URI与location表达式匹配前,修改请求的URI的HTTP阶段,可自定义handler处理方法 */ NGX_HTTP_SERVER_REWRITE_PHASE, /* 根据请求的URI寻找匹配的location表达式,只能由ngx_http_core_module模块实现, * 且不可自定义handler处理方法 */ NGX_HTTP_FIND_CONFIG_PHASE, /* 在NGX_HTTP_FIND_CONFIG_PHASE阶段寻找到匹配的location之后再修改请求的URI, * 可自定义handler处理方法 */ NGX_HTTP_REWRITE_PHASE, /* 在rewrite重写URI后,防止错误的nginx.conf配置导致死循环, * 只能用ngx_http_core_module模块处理,不可自定义handler处理方法 */ NGX_HTTP_POST_REWRITE_PHASE, /* 在处理NGX_HTTP_ACCESS_PHASE阶段决定请求的访问权限前,处理该阶段,可自定义handler处理方法 */ NGX_HTTP_PREACCESS_PHASE, /* 由HTTP模块判断是否允许请求访问Nginx服务器,可自定义handler处理方法 */ NGX_HTTP_ACCESS_PHASE, /* 向用户发送拒绝服务的错误响应,不可自定义handler处理方法 */ NGX_HTTP_POST_ACCESS_PHASE, /* 使请求顺序的访问多个静态文件资源,不可自定义handler处理方法 */ NGX_HTTP_TRY_FILES_PHASE, /* 处理HTTP请求内容,可自定义handler处理方法 */ NGX_HTTP_CONTENT_PHASE, /* 处理完请求后记录日志阶段,可自定义handler处理方法 */ NGX_HTTP_LOG_PHASE } ngx_http_phases;
每个HTTP的checker方法与handler处理如下所示:
typedef struct ngx_http_phase_handler_s ngx_http_phase_handler_t; typedef ngx_int_t (*ngx_http_phase_handler_pt)(ngx_http_request_t *r, ngx_http_phase_handler_t *ph); struct ngx_http_phase_handler_s { /* * 在HTTP框架中所有的checker方法都有ngx_http_core_module模块实现,其他普通模块不能对其重定义; * 在处理某一个HTTP阶段时,HTTP框架会首先调用checker方法,然后在checker方法里面再调用handler方法; */ ngx_http_phase_handler_pt checker; /* 由HTTP模块实现的handler方法处理HTTP阶段,一般用于普通HTTP模块 */ ngx_http_handler_pt handler; /* 下一个将要执行的HTTP阶段 */ ngx_uint_t next; };
完成 http{} 块的解析后,根据 nginx.conf 文件中配置产生由 ngx_http_phase_handler_t 组成的数组,在处理 HTTP 请求时,一般情况下按照阶段的方向顺序 phase handler 加入到回调表中。ngx_http_phase_engine_t 结构体由所有 ngx_http_phase_handler_t 组成的数组,如下所示:
typedef struct { /* 由ngx_http_phase_handler_t 构成的数组首地址, * 表示一个请求可能经历的所有ngx_http_handler_pt处理方法 */ ngx_http_phase_handler_t *handlers; /* 表示NGX_HTTP_SERVER_REWRITE_PHASE阶段第一个ngx_http_phase_handler_pt处理方法在handlers数组中的序号;*/ ngx_uint_t server_rewrite_index; /* 表示NGX_HTTP_REWRITE_PHASE阶段第一个ngx_http_phase_handler_pt处理方法在handlers数组中的序号;*/ ngx_uint_t location_rewrite_index; } ngx_http_phase_engine_t;
ngx_http_phase_engine_t 中保存在当前 nginx.conf 配置下,一个用户请求可能经历的所有 ngx_http_handler_pt 处理方法。
typedef struct { /* 保存在每一个HTTP模块初始化时添加到当前阶段的处理方法 */ ngx_array_t handlers; } ngx_http_phase_t;
在 HTTP模块初始化过程中,HTTP模块通过postconfiguration方法将自定义的方法添加到handler数组中,即该方法会被添加到phase_engine数组中。下面以NGX_HTTP_POST_READ_PHASE阶段为例,讲解了该阶段的 checker方法的实现:
ngx_int_t ngx_http_core_generic_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) { ngx_int_t rc; /* * generic phase checker, * used by the post read and pre-access phases */ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "generic phase: %ui", r->phase_handler); /* 调用当前阶段各HTTP模块中的handler处理方法 */ rc = ph->handler(r); /* 进入下一阶段处理,忽略当前阶段其他的处理方法 */ if (rc == NGX_OK) { r->phase_handler = ph->next; return NGX_AGAIN; } /* 进入下一个处理方法,该处理方法可能属于当前阶段,也可能属于下一个阶段 */ if (rc == NGX_DECLINED) { r->phase_handler++; return NGX_AGAIN; } /* 当前请求依旧处于当前处理阶段 */ if (rc == NGX_AGAIN || rc == NGX_DONE) { return NGX_OK; } /* rc == NGX_ERROR || rc == NGX_HTTP_... */ /* 若出错,结束请求 */ ngx_http_finalize_request(r, rc); return NGX_OK; }
以上就介绍了Nginx 中 HTTP模块初始化,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen

Auf dem Anmeldebildschirm wird die Meldung „Ihre Organisation hat Sie gebeten, Ihre PIN zu ändern“ angezeigt. Dies geschieht, wenn das PIN-Ablauflimit auf einem Computer erreicht wird, der organisationsbasierte Kontoeinstellungen verwendet und die Kontrolle über persönliche Geräte hat. Wenn Sie Windows jedoch über ein persönliches Konto einrichten, sollte die Fehlermeldung im Idealfall nicht erscheinen. Obwohl dies nicht immer der Fall ist. Die meisten Benutzer, die auf Fehler stoßen, melden dies über ihre persönlichen Konten. Warum fordert mich meine Organisation auf, meine PIN unter Windows 11 zu ändern? Es ist möglich, dass Ihr Konto mit einer Organisation verknüpft ist. Ihr primärer Ansatz sollte darin bestehen, dies zu überprüfen. Die Kontaktaufnahme mit Ihrem Domain-Administrator kann hilfreich sein! Darüber hinaus können falsch konfigurierte lokale Richtlinieneinstellungen oder falsche Registrierungsschlüssel Fehler verursachen. Im Augenblick

Windows 11 bringt frisches und elegantes Design in den Vordergrund; die moderne Benutzeroberfläche ermöglicht es Ihnen, feinste Details, wie zum Beispiel Fensterränder, zu personalisieren und zu ändern. In diesem Leitfaden besprechen wir Schritt-für-Schritt-Anleitungen, die Ihnen dabei helfen, eine Umgebung zu erstellen, die Ihrem Stil im Windows-Betriebssystem entspricht. Wie ändere ich die Fensterrahmeneinstellungen? Drücken Sie +, um die Einstellungen-App zu öffnen. WindowsIch gehe zu Personalisierung und klicke auf Farbeinstellungen. Farbänderung Fensterränder Einstellungen Fenster 11" Breite="643" Höhe="500" > Suchen Sie die Option Akzentfarbe auf Titelleiste und Fensterrändern anzeigen und schalten Sie den Schalter daneben um. Um Akzentfarben im Startmenü und in der Taskleiste anzuzeigen Um die Designfarbe im Startmenü und in der Taskleiste anzuzeigen, aktivieren Sie „Design im Startmenü und in der Taskleiste anzeigen“.

Miniaturansichten in der Taskleiste können Spaß machen, aber auch ablenken oder stören. Wenn man bedenkt, wie oft Sie mit der Maus über diesen Bereich fahren, haben Sie möglicherweise ein paar Mal versehentlich wichtige Fenster geschlossen. Ein weiterer Nachteil besteht darin, dass es mehr Systemressourcen verbraucht. Wenn Sie also nach einer Möglichkeit suchen, ressourceneffizienter zu arbeiten, zeigen wir Ihnen, wie Sie es deaktivieren können. Wenn Ihre Hardware-Spezifikationen jedoch dafür geeignet sind und Ihnen die Vorschau gefällt, können Sie sie aktivieren. Wie aktiviere ich die Miniaturvorschau der Taskleiste in Windows 11? 1. Tippen Sie in der App „Einstellungen“ auf die Taste und klicken Sie auf „Einstellungen“. Klicken Sie unter Windows auf „System“ und wählen Sie „Info“. Klicken Sie auf Erweiterte Systemeinstellungen. Navigieren Sie zur Registerkarte „Erweitert“ und wählen Sie unter „Leistung“ die Option „Einstellungen“ aus. Wählen Sie „Visuelle Effekte“

Wir alle haben unterschiedliche Vorlieben, wenn es um die Anzeigeskalierung unter Windows 11 geht. Manche Leute mögen große Symbole, andere mögen kleine Symbole. Wir sind uns jedoch alle einig, dass die richtige Skalierung wichtig ist. Eine schlechte Schriftartenskalierung oder eine Überskalierung von Bildern kann bei der Arbeit ein echter Produktivitätskiller sein. Sie müssen daher wissen, wie Sie sie anpassen können, um die Fähigkeiten Ihres Systems optimal zu nutzen. Vorteile des benutzerdefinierten Zooms: Dies ist eine nützliche Funktion für Personen, die Schwierigkeiten haben, Text auf dem Bildschirm zu lesen. Es hilft Ihnen, mehr gleichzeitig auf dem Bildschirm zu sehen. Sie können benutzerdefinierte Erweiterungsprofile erstellen, die nur für bestimmte Monitore und Anwendungen gelten. Kann dazu beitragen, die Leistung von Low-End-Hardware zu verbessern. Dadurch haben Sie mehr Kontrolle darüber, was auf Ihrem Bildschirm angezeigt wird. So verwenden Sie Windows 11

Die Bildschirmhelligkeit ist ein wesentlicher Bestandteil der Nutzung moderner Computergeräte, insbesondere wenn Sie über einen längeren Zeitraum auf den Bildschirm schauen. Es hilft Ihnen, die Belastung Ihrer Augen zu reduzieren, die Lesbarkeit zu verbessern und Inhalte einfach und effizient anzuzeigen. Abhängig von Ihren Einstellungen kann es jedoch manchmal schwierig sein, die Helligkeit zu verwalten, insbesondere unter Windows 11 mit den neuen Änderungen an der Benutzeroberfläche. Wenn Sie Probleme beim Anpassen der Helligkeit haben, finden Sie hier alle Möglichkeiten, die Helligkeit unter Windows 11 zu verwalten. So ändern Sie die Helligkeit unter Windows 11 [10 Möglichkeiten erklärt] Benutzer eines einzelnen Monitors können die folgenden Methoden verwenden, um die Helligkeit unter Windows 11 anzupassen. Hierzu zählen sowohl Desktop-Systeme mit einem einzelnen Monitor als auch Laptops. Lasst uns beginnen. Methode 1: Verwenden Sie das Action Center. Das Action Center ist zugänglich

Mit iOS 17 hat Apple mehrere neue Datenschutz- und Sicherheitsfunktionen in sein mobiles Betriebssystem eingeführt, darunter die Möglichkeit, eine zweistufige Authentifizierung für private Browser-Tabs in Safari zu verlangen. Hier erfahren Sie, wie es funktioniert und wie Sie es ausschalten. Auf einem iPhone oder iPad mit iOS 17 oder iPadOS 17 erfordert der Browser von Apple jetzt eine Face ID/Touch ID-Authentifizierung oder einen Passcode, wenn Sie in Safari eine Registerkarte „Privates Surfen“ geöffnet haben und dann die Sitzung oder App verlassen, um erneut darauf zuzugreifen. Mit anderen Worten: Wenn jemand Ihr iPhone oder iPad in die Hände bekommt, während es entsperrt ist, kann er Ihre Privatsphäre trotzdem nicht einsehen, ohne Ihren Passcode zu kennen

Der HTTP-Statuscode 520 bedeutet, dass der Server bei der Verarbeitung der Anfrage einen unbekannten Fehler festgestellt hat und keine genaueren Informationen bereitstellen kann. Wird verwendet, um darauf hinzuweisen, dass bei der Verarbeitung der Anforderung durch den Server ein unbekannter Fehler aufgetreten ist, der durch Serverkonfigurationsprobleme, Netzwerkprobleme oder andere unbekannte Gründe verursacht werden kann. Dies wird normalerweise durch Serverkonfigurationsprobleme, Netzwerkprobleme, Serverüberlastung oder Codierungsfehler verursacht. Wenn Sie auf einen Fehler mit dem Statuscode 520 stoßen, wenden Sie sich am besten an den Website-Administrator oder das technische Support-Team, um weitere Informationen und Unterstützung zu erhalten.

Das berühmte Aktivierungsskript MAS2.2 unterstützt wieder die digitale Aktivierung. Die Methode stammt von @asdcorp und der MAS-Autor nennt sie HWID2. Laden Sie „gatherosstate.exe“ (kein Original, geändert) von https://github.com/massgravel/Microsoft-Activation-Scripts herunter, führen Sie es mit Parametern aus und generieren Sie GenuineTicket.xml. Schauen Sie sich zunächst die ursprüngliche Methode an: Gatherosstate.exePfn=xxxxxxx;DownlevelGenuineState=1 und vergleichen Sie sie dann mit der neuesten Methode: Gatheros
