最近需要研究Nginx HTTP请求处理的流程,找到一篇细节文章
Nginx在7层负载交换、反向代理服务领域使用比较广泛。Nginx的结构也比较简单,除了底层几个核心的模块(如ngx_core_module,ngx_event_core_module,ngx_errlog_module等)之外,其它的主要是基于上述核心模块的http和mail的模块组,负责处理相关服务。而这些模块也可以在编译的时候被enable/disable,取决于对实际功能的需求。在这里,我来分析一下Nginx用的最多的功能,即处理http请求的工作流程。
在事件处理的分析中,提到过当有http请求过来时事件的触发和处理过程。我们知道,在一个子进程accept()请求之后,会调用ngx_http_init_connection()函数。这个函数会添加一个读事件,并设置其handler为ngx_http_init_request()。但是,对于http模块的载入以及初始化,却是要从http_block()开始。在父进程(master process)调用ngx_init_cycle()的时候,会调用一次ngx_conf_parse()函数(先不在这里分析),这个时候(解析到了"http {...}" block),ngx_http_module模块的set()函数即ngx_http_block()就被调用。
- static char * ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
- {
-
-
-
- ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
- *(ngx_http_conf_ctx_t **) conf = ctx;
-
- 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++;
- }
-
-
- 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);
-
-
- for (;;) {
-
- module = ngx_modules[m]->ctx;
- mi = ngx_modules[m]->ctx_index;
-
-
-
-
- ctx->main_conf[mi] = module->create_main_conf(cf);
- ctx->srv_conf[mi] = module->create_srv_conf(cf);
- ctx->loc_conf[mi] = module->create_loc_conf(cf);
- }
- pcf = *cf;
- cf->ctx = ctx;
- for (;;) {
-
-
- module->preconfiguration(cf);
- }
-
- cf->module_type = NGX_HTTP_MODULE;
- cf->cmd_type = NGX_HTTP_MAIN_CONF;
- rv = ngx_conf_parse(cf, NULL);
-
- cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
- cscfp = cmcf->servers.elts;
- for (;;) {
-
- rv = module->init_main_conf(cf, ctx->main_conf[mi]);
- rv = ngx_http_merge_servers(cf, cmcf, module, mi);
- }
-
-
- for (s = 0; s < cmcf->servers.nelts; s++) {
- clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
-
- ngx_http_init_locations(cf, cscfp[s], clcf);
-
-
- ngx_http_init_static_location_trees(cf, clcf);
- }
-
- 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 (;;) {
-
-
-
- module->postconfiguration(cf);
- }
-
- if (ngx_http_variables_init_vars(cf) != NGX_OK) {
- return NGX_CONF_ERROR;
- }
-
-
- if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {
- return NGX_CONF_ERROR;
- }
-
-
- if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) {
- return NGX_CONF_ERROR;
- }
- return NGX_CONF_OK;
- }
当nginx收到请求的时候,就会调用(1)ngx_http_init_request,开始了对请求的处理过程。
- static void ngx_http_init_request(ngx_event_t *rev)
- {
-
- c = rev->data;
-
-
-
- hc = c->data;
-
-
-
- r = hc->request;
-
-
-
- c->data = r;
- r->http_connection = hc;
- c->sent = 0;
- r->signature = NGX_HTTP_MODULE;
-
-
- port = c->listening->servers;
- r->connection = c;
-
-
- if (port->naddrs > 1) {
-
-
-
-
-
- if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
- ngx_http_close_connection(c);
- return;
- }
- switch (c->local_sockaddr->sa_family) {
- default:
- sin = (struct sockaddr_in *) c->local_sockaddr;
- addr = port->addrs;
-
- for (i = 0; i < port->naddrs - 1; i++) {
- if (addr[i].addr == sin->sin_addr.s_addr) {
- break;
- }
- }
- addr_conf = &addr[i].conf;
- break;
- }
- }
- else {
- switch (c->local_sockaddr->sa_family) {
- default:
- addr = port->addrs;
- addr_conf = &addr[0].conf;
- break;
- }
- }
- r->virtual_names = addr_conf->virtual_names;
-
- cscf = addr_conf->core_srv_conf;
- r->main_conf = cscf->ctx->main_conf;
- r->srv_conf = cscf->ctx->srv_conf;
- r->loc_conf = cscf->ctx->loc_conf;
-
- rev->handler = ngx_http_process_request_line;
-
- r->read_event_handler = ngx_http_block_reading;
- clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
- c->log->file = clcf->error_log->file;
-
- r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);
- cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
-
- r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts *
- sizeof(ngx_http_variable_value_t));
- c->single_connection = 1;
- c->destroyed = 0;
-
-
- r->main = r;
- r->method = NGX_HTTP_UNKNOWN;
- r->headers_in.content_length_n = -1;
- r->headers_in.keep_alive_n = -1;
- r->headers_out.content_length_n = -1;
- r->headers_out.last_modified_time = -1;
- r->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1;
- r->subrequests = NGX_HTTP_MAX_SUBREQUESTS + 1;
- r->http_state = NGX_HTTP_READING_REQUEST_STATE;
- ctx = c->log->data;
- ctx->request = r;
- ctx->current_request = r;
- r->log_handler = ngx_http_log_error_handler;
- rev->handler(rev);
- }
下面,分别调用了下列函数,在这里不一一详细分析:
-->(2)ngx_http_process_request_line()//读取、解析请求行,并存入r的相应成员(如uri,args相关的重要指针)。
-->(3)ngx_http_process_request_headers()//把header line逐行解析并以key-value形式存入r。
-->(4)ngx_http_process_request()
-->(5)ngx_http_handler()
-->(6)ngx_http_core_run_phases()
- void ngx_http_core_run_phases(ngx_http_request_t *r)
- {
- cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
- ph = cmcf->phase_engine.handlers;
-
-
-
-
-
- while (ph[r->phase_handler].checker) {
-
- rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
- if (rc == NGX_OK) {
- return;
- }
- }
- }
关于ngx_http_core_main_conf_t,它里面有两个成员,phase_engine和phases。其中phases是一个存放所有模块的在postconfiguration()函数里面注册的相关phase的handler。比如,ngx_http_index_module里面,就push了一个NGX_HTTP_CONTENT_PHASE的handler:ngx_http_index_handler。这个handler就被存放在ngx_http_core_main_conf_t的phases[NGX_HTTP_CONTENT_PHASE]这个数组里面。而phase_engine里面的handlers(ngx_http_phase_handler_s类型)则是一个checker和handler的函数对,next指向下一个phase在phase_engine里面的index。
比如说,最基本的一个处理过程:NGX_HTTP_FIND_CONFIG_PHASE --> NGX_HTTP_PREACCESS_PHASE --> NGX_HTTP_ACCESS_PHASE --> NGX_HTTP_CONTENT_PHASE。被调用的函数是:
-
- ngx_http_core_find_config_phase()
- {
-
- ngx_http_core_find_location();
-
-
- ngx_http_update_location_config();
-
- r->phase_handler++;
- }
NGX_HTTP_PREACCESS_PHASE的checker是ngx_http_core_generic_phase(),即调用ph->handler(r)。在默认的模块配置里,NGX_HTTP_PREACCESS_PHASE类型的有ngx_http_limit_req_module和ngx_http_limit_zone_module两个模块,那么它们的ngx_http_limit_req_handler()和ngx_http_limit_zone_handler()就会被调用。在ngx_http_core_generic_phase()里面调用ph->handler(r)之后即控制下一个被调用的函数(是到下一个phase或者是本个phase的下一个handler)。
-
- ngx_http_core_access_phase()
- {
- rc = ph->handler(r);
-
-
- }
在模块的默认配置里,NGX_HTTP_ACCESS_PHASE类型的是ngx_http_access_module和ngx_http_auth_basic_module,即ph->handler(r)调用了ngx_http_access_handler()和ngx_http_auth_basic_handler()
-
- ngx_http_core_content_phase()
- {
-
-
- if (r->content_handler) {
- r->write_event_handler = ngx_http_request_empty_handler;
- ngx_http_finalize_request(r, r->content_handler(r));
- return NGX_OK;
- }
-
- rc = ph->handler(r);
- ph++;
-
- if (ph->checker) {
- r->phase_handler++;
- return NGX_AGAIN;
- }
-
- }
默认的配置里有3个NGX_HTTP_CONTENT_PHASE类型的模块有ngx_http_static_module,ngx_http_index_module和ngx_http_autoindex_module,调用它们的ngx_http_static_handler(),ngx_http_index_handler()和ngx_http_autoindex_handler()。
通过实际运行的的debug信息,可以看到每个phase的checker被调用时候的handler的r->phase_handler(即index)。根据实际的情况(如根据不同location配置),不一定每个handler都会被调用(通过设置r->phase_handler = ph->next),甚至有时候会直接跳到另外一个phase(比如在ngx_http_index_handler()里面调用ngx_http_internal_redirect(),重新进入ngx_http_handler(),即重新把phase走一遍)。这些都是根据每个phase的handler的实现以及实际的请求来决定的。
关于每个phase的具体功能:
- typedef enum {
-
- NGX_HTTP_POST_READ_PHASE = 0,
-
- NGX_HTTP_SERVER_REWRITE_PHASE,
-
-
- NGX_HTTP_FIND_CONFIG_PHASE,
-
- NGX_HTTP_REWRITE_PHASE,
-
- NGX_HTTP_POST_REWRITE_PHASE,
-
- NGX_HTTP_PREACCESS_PHASE,
-
- NGX_HTTP_ACCESS_PHASE,
-
- NGX_HTTP_POST_ACCESS_PHASE,
-
- NGX_HTTP_TRY_FILES_PHASE,
-
- NGX_HTTP_CONTENT_PHASE,
-
- NGX_HTTP_LOG_PHASE
- } ngx_http_phases;
Nginx的http上下文(在读取配置的时候设置):
阅读(1956) | 评论(0) | 转发(0) |