nginx 11个处理阶段


  nginx的源码确实比较难读,怎么说呢, 一大堆的函数回调指针,没有理清脉络,看源码就很费劲。

首先要弄清楚的就是要理顺nginx调用的主框架,nginx是以配置为中心的处理架构,想读懂,先了解配置。

   言归正传,这里说nginx处理的是一个阶段,

       


  1. typedef enum {  
  2.     NGX_HTTP_POST_READ_PHASE = 0,   //读取请求头  
  3.   
  4.     NGX_HTTP_SERVER_REWRITE_PHASE,   //执行rewrite  
  5.   
  6.     NGX_HTTP_FIND_CONFIG_PHASE,  //根据uri替换location  
  7.     NGX_HTTP_REWRITE_PHASE,      //根据替换结果继续执行rewrite  
  8.     NGX_HTTP_POST_REWRITE_PHASE, //执行rewrite后处理  
  9.   
  10.     NGX_HTTP_PREACCESS_PHASE,    //认证预处理   请求限制,连接限制  
  11.   
  12.     NGX_HTTP_ACCESS_PHASE,       //认证处理  
  13.     NGX_HTTP_POST_ACCESS_PHASE,  //认证后处理, 认证不通过, 丢包  
  14.   
  15.     NGX_HTTP_TRY_FILES_PHASE,    //尝试try标签  
  16.     NGX_HTTP_CONTENT_PHASE,      //内容处理  
  17.   
  18.     NGX_HTTP_LOG_PHASE           //日志处理  
  19. } ngx_http_phases;  


以上每个阶段的处理都是一个数组回调。数据的初始化如下:


  1. static ngx_int_t  
  2. ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)  
  3. {  
  4.     if (ngx_array_init(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers,  
  5.                        cf->pool, 1, sizeof(ngx_http_handler_pt))  
  6.         != NGX_OK)  
  7.     {  
  8.         return NGX_ERROR;  
  9.     }  
  10.   
  11.     if (ngx_array_init(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers,  
  12.                        cf->pool, 1, sizeof(ngx_http_handler_pt))  
  13.         != NGX_OK)  
  14.     {  
  15.         return NGX_ERROR;  
  16.     }  
  17.   
  18.     if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers,  
  19.                        cf->pool, 1, sizeof(ngx_http_handler_pt))  
  20.         != NGX_OK)  
  21.     {  
  22.         return NGX_ERROR;  
  23.     }  
  24.   
  25.     if (ngx_array_init(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers,  
  26.                        cf->pool, 1, sizeof(ngx_http_handler_pt))  
  27.         != NGX_OK)  
  28.     {  
  29.         return NGX_ERROR;  
  30.     }  
  31.   
  32.     if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers,  
  33.                        cf->pool, 2, sizeof(ngx_http_handler_pt))  
  34.         != NGX_OK)  
  35.     {  
  36.         return NGX_ERROR;  
  37.     }  
  38.   
  39.     if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers,  
  40.                        cf->pool, 4, sizeof(ngx_http_handler_pt))  
  41.         != NGX_OK)  
  42.     {  
  43.         return NGX_ERROR;  
  44.     }  
  45.   
  46.     if (ngx_array_init(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers,  
  47.                        cf->pool, 1, sizeof(ngx_http_handler_pt))  
  48.         != NGX_OK)  
  49.     {  
  50.         return NGX_ERROR;  
  51.     }  
  52.   
  53.     return NGX_OK;  
  54. }  


可以看到

  1. NGX_HTTP_FIND_CONFIG_PHASE,  //根据uri替换location  
  2. NGX_HTTP_POST_REWRITE_PHASE, //执行rewrite后处理  
  3. NGX_HTTP_POST_ACCESS_PHASE,  //认证后处理, 认证不通过, 丢包  

以上几个阶段都没有做数组的初始化化。

还要说一点的是,真正执行的时候,并不是调用cmcf->phases处理的, 而是调用cmcf->phase_engine.handlers
  1. void  
  2. ngx_http_core_run_phases(ngx_http_request_t *r)  
  3. {  
  4.     ngx_int_t                   rc;  
  5.     ngx_http_phase_handler_t   *ph;  
  6.     ngx_http_core_main_conf_t  *cmcf;  
  7.   
  8.     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);  
  9.   
  10.     ph = cmcf->phase_engine.handlers;  
  11.   
  12.     while (ph[r->phase_handler].checker) {  
  13.   
  14.         rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);  
  15.   
  16.         if (rc == NGX_OK) {  //只要return不为NGX_OK就继续执行。  
  17.             return;  
  18.         }  
  19.     }  
  20. }  

phase_engine的初始化如下

  1. static ngx_int_t  
  2. ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)  
  3. {  
  4.     ngx_int_t                   j;  
  5.     ngx_uint_t                  i, n;  
  6.     ngx_uint_t                  find_config_index, use_rewrite, use_access;  
  7.     ngx_http_handler_pt        *h;  
  8.     ngx_http_phase_handler_t   *ph;  
  9.     ngx_http_phase_handler_pt   checker;  
  10.   
  11.     cmcf->phase_engine.server_rewrite_index = (ngx_uint_t) -1;  
  12.     cmcf->phase_engine.location_rewrite_index = (ngx_uint_t) -1;  
  13.     find_config_index = 0;  
  14.     use_rewrite = cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers.nelts ? 1 : 0;  
  15.     use_access = cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0;  
  16.   
  17.     n = use_rewrite + use_access + cmcf->try_files + 1 /* find config phase */;  
  18.   
  19.     for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {  
  20.         n += cmcf->phases[i].handlers.nelts;  
  21.     }  
  22.   
  23.     ph = ngx_pcalloc(cf->pool,  
  24.                      n * sizeof(ngx_http_phase_handler_t) + sizeof(void *));  
  25.     if (ph == NULL) {  
  26.         return NGX_ERROR;  
  27.     }  
  28.   
  29.     cmcf->phase_engine.handlers = ph;  
  30.     n = 0;  
  31.   
  32.     for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {  
  33.         h = cmcf->phases[i].handlers.elts;  
  34.   
  35.         switch (i) {  
  36.   
  37.         case NGX_HTTP_SERVER_REWRITE_PHASE:  
  38.             if (cmcf->phase_engine.server_rewrite_index == (ngx_uint_t) -1) {  
  39.                 cmcf->phase_engine.server_rewrite_index = n;  
  40.             }  
  41.             checker = ngx_http_core_rewrite_phase;  
  42.   
  43.             break;  
  44.   
  45.         case NGX_HTTP_FIND_CONFIG_PHASE:  
  46.             find_config_index = n;  
  47.   
  48.             ph->checker = ngx_http_core_find_config_phase;  
  49.             n++;  
  50.             ph++;  
  51.   
  52.             continue;  
  53.   
  54.         case NGX_HTTP_REWRITE_PHASE:  
  55.             if (cmcf->phase_engine.location_rewrite_index == (ngx_uint_t) -1) {  
  56.                 cmcf->phase_engine.location_rewrite_index = n;  
  57.             }  
  58.             checker = ngx_http_core_rewrite_phase;  
  59.   
  60.             break;  
  61.   
  62.         case NGX_HTTP_POST_REWRITE_PHASE:  
  63.             if (use_rewrite) {  
  64.                 ph->checker = ngx_http_core_post_rewrite_phase;  
  65.                 ph->next = find_config_index;  
  66.                 n++;  
  67.                 ph++;  
  68.             }  
  69.   
  70.             continue;  
  71.   
  72.         case NGX_HTTP_ACCESS_PHASE:  
  73.             checker = ngx_http_core_access_phase;  
  74.             n++;  
  75.             break;  
  76.   
  77.         case NGX_HTTP_POST_ACCESS_PHASE:  
  78.             if (use_access) {  
  79.                 ph->checker = ngx_http_core_post_access_phase;  
  80.                 ph->next = n;  
  81.                 ph++;  
  82.             }  
  83.   
  84.             continue;  
  85.   
  86.         case NGX_HTTP_TRY_FILES_PHASE:  
  87.             if (cmcf->try_files) {  
  88.                 ph->checker = ngx_http_core_try_files_phase;  
  89.                 n++;  
  90.                 ph++;  
  91.             }  
  92.   
  93.             continue;  
  94.   
  95.         case NGX_HTTP_CONTENT_PHASE:  
  96.             checker = ngx_http_core_content_phase;  
  97.             break;  
  98.   
  99.         default:  
  100.             checker = ngx_http_core_generic_phase;  
  101.         }  
  102.   
  103.         n += cmcf->phases[i].handlers.nelts;  
  104.   
  105.         for (j = cmcf->phases[i].handlers.nelts - 1; j >=0; j--) {  
  106.             ph->checker = checker;  
  107.             ph->handler = h[j];  //数组是反向赋值的,刚好对应了数组操作的顺序  
  108.             ph->next = n;        //next永远执行下一个阶段的执行索引  
  109.             ph++;  
  110.         }  
  111.     }  
  112.   
  113.     return NGX_OK;  
  114. }  

从上面可以看到,nginx把所有阶段的回调函数组成了一个串行的执行函数数组。
cheker指针指向检测调用函数指针,hander指向该阶段的函数调用指针,next则指向下一阶段的ph索引。
当执行某一阶段到一半的时候,想跳到下一个阶段,只需要r->phase_handler = ph->next;

ph的返回值为NGX_OK时, 函数会跳出阶段的执行,但是在阶段执行的hander中却不是这样的。

NGX_DECLINED:   会直接执行下一个ph调用。
NGX_AGAIN:  会重复调用本ph
NGX_DOWN:终止阶段函数回调调用。
...more

  • Author

    12 days ago | Profile | #

    Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.