源码:nginx 1.12.0
nginx由于其高性能、扩充性好等特点在迅速走红,越来越多的公司采用nginx作web服务器、负载均衡、waf等 工作,一些基于nginx二次开发的openresty、tengine等开源软件也迅速在相关领域走红。
虽然nginx有对应的windows版本,但是不建议使用。因为windows环境下缺少epoll(linux)、devpoll(bsd)这样高效的事件通知方案,实际性能与linux/BSD环境下的差别很多。关于nginx的event模块这篇文章不展开讲,这里主要讲nginx能实现负载均衡、waf等不同功能的原因——http module。
http模块整体处理流程如下:
根据上图,phase handler以及filter各个类型的主要初始化工作就是在postconfiguration函数中,下面代码片段中也有介绍。
一、phase handlers阶段
nginx对http的请求处理分成了POST_READ, SERVER_REWRITE, FIND_CONFIG, REWRITE, POST_REWRITE, PREACCESS, ACCESS, POST_ACCESS, TRY_FILES, CONTENT, LOG这几个阶段,除了FIND_CONFIG, POST_WRITE, POST_ACCESS, TRY_FILES这四个阶段用户不能添加自定义的处理函数,其余每个阶段都初始化了一个数组用于保存本阶段的处理函数指针。如下:
////// nginx/src/http/ngx_http.c //////// static ngx_int_t ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) { if (ngx_array_init(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers, cf->pool, 1, sizeof(ngx_http_handler_pt)) != NGX_OK) { return NGX_ERROR; } ..... ..... if (ngx_array_init(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers, cf->pool, 1, sizeof(ngx_http_handler_pt)) != NGX_OK) { return NGX_ERROR; } return NGX_OK; } ///// nginx/src/http/modules/ngx_http_rewrite_module.c ///// static ngx_int_t ngx_http_rewrite_init(ngx_conf_t *cf) { ngx_http_handler_pt *h; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); //在&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers指向的数组中申请一个函数指针空间 h = ngx_array_push(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers); if (h == NULL) { return NGX_ERROR; } //将函数添加到数组中新申请的元素中 *h = ngx_http_rewrite_handler; h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers); if (h == NULL) { return NGX_ERROR; } *h = ngx_http_rewrite_handler; return NGX_OK; } ////// nginx/src/http/ngx_http.c //////// static ngx_int_t ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) { cmcf->phase_engine.server_rewrite_index = (ngx_uint_t) -1; cmcf->phase_engine.location_rewrite_index = (ngx_uint_t) -1; find_config_index = 0; use_rewrite = cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers.nelts ? 1 : 0; use_access = cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0; n = use_rewrite + use_access + cmcf->try_files + 1 /* find config phase */; for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) { n += cmcf->phases[i].handlers.nelts; } //为phase ph = ngx_pcalloc(cf->pool, n * sizeof(ngx_http_phase_handler_t) + sizeof(void *)); if (ph == NULL) { return NGX_ERROR; } cmcf->phase_engine.handlers = ph; n = 0; for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) { h = cmcf->phases[i].handlers.elts; switch (i) { case NGX_HTTP_SERVER_REWRITE_PHASE: if (cmcf->phase_engine.server_rewrite_index == (ngx_uint_t) -1) { cmcf->phase_engine.server_rewrite_index = n; } //根据phase阶段确定每个阶段对应的checker checker = ngx_http_core_rewrite_phase; break; ..... ..... case NGX_HTTP_CONTENT_PHASE: checker = ngx_http_core_content_phase; break; default: checker = ngx_http_core_generic_phase; } n += cmcf->phases[i].handlers.nelts; //遍历各个phase handlers数组中的注册函数并统一添加到cmcf->phase_engine.handlers中 for (j = cmcf->phases[i].handlers.nelts - 1; j >=0; j--) { ph->checker = checker; ph->handler = h[j]; ph->next = n; ph++; } } return NGX_OK; } ///// nginx/src/http/ngx_http_core_module.c //////// void ngx_http_core_run_phases(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_phase_handler_t *ph; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); ph = cmcf->phase_engine.handlers; while (ph[r->phase_handler].checker) { //根据请求中的phase索引确定执行的checker函数 //checker函数根据处理结果来决定是结束处理还是继续下一个phase rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]); if (rc == NGX_OK) { return; } } }
二、filter类型模块
filter类型主要是在输出的时候对输出内容进行处理,filter类型的各个模块的调用顺序与phase handler类型(根据phase阶段顺序)不同,filter类型的各个模块是通过链表的形式联系到一块的,只有链表头ngx_http_top_body_filter 函数指针是全局的,遍历顺序跟在配置文件定义的顺序(nginx/auto/modules中ngx_module_order)相反。
在各个module初始化的时候,会将ngx_http_top_body_filter指针的值保存到ngx_http_next_body_filter局部变量中,然后把当前filter的处理函数赋值给ngx_http_top_body_filter,同时每个filter的处理函数中都将ngx_http_next_body_filter的值赋值给ctx->output_filter,以便可以顺序遍历各个filter。
对于ngx_http_write_filter_module、ngx_http_header_filter_module两个模块中没有ngx_http_next_body_filter变量,是因为ngx_http_write_filter_module是最后一个filter模块,因此不用next。ngx_http_header_filter_module虽然是倒数第二个模块,但是filter函数中调用了write_filter的函数,因此也没有使用next。
///// nginx/src/http/ngx_http_core_module.c /////// ngx_int_t ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in) { ..... //通过链表接口来一次遍历各个filter模块进行处理 rc = ngx_http_top_body_filter(r, in); ..... return rc; } ///// nginx/src/http/ngx_http_copy_filter_module.c ////////// static ngx_int_t ngx_http_copy_filter_init(ngx_conf_t *cf) { ngx_http_next_body_filter = ngx_http_top_body_filter; ngx_http_top_body_filter = ngx_http_copy_filter; return NGX_OK; } static ngx_int_t ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) { ..... ..... ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); if (ctx == NULL) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } ngx_http_set_ctx(r, ctx, ngx_http_copy_filter_module); //记录下一个要执行的filter ctx->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_body_filter; ctx->filter_ctx = r; .... .... if (in && in->buf && ngx_buf_size(in->buf)) { r->request_output = 1; } } ..... rc = ngx_output_chain(ctx, in); ..... return rc; }