nginx的十一个阶段处理

原创 2014年04月19日 00:46:47

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

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

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

       

typedef enum {
    NGX_HTTP_POST_READ_PHASE = 0,   //读取请求头

    NGX_HTTP_SERVER_REWRITE_PHASE,   //执行rewrite

    NGX_HTTP_FIND_CONFIG_PHASE,  //根据uri替换location
    NGX_HTTP_REWRITE_PHASE,      //根据替换结果继续执行rewrite
    NGX_HTTP_POST_REWRITE_PHASE, //执行rewrite后处理

    NGX_HTTP_PREACCESS_PHASE,    //认证预处理   请求限制,连接限制

    NGX_HTTP_ACCESS_PHASE,       //认证处理
    NGX_HTTP_POST_ACCESS_PHASE,  //认证后处理, 认证不通过, 丢包

    NGX_HTTP_TRY_FILES_PHASE,    //尝试try标签
    NGX_HTTP_CONTENT_PHASE,      //内容处理

    NGX_HTTP_LOG_PHASE           //日志处理
} ngx_http_phases;

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

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_SERVER_REWRITE_PHASE].handlers,
                       cf->pool, 1, sizeof(ngx_http_handler_pt))
        != NGX_OK)
    {
        return NGX_ERROR;
    }

    if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers,
                       cf->pool, 1, sizeof(ngx_http_handler_pt))
        != NGX_OK)
    {
        return NGX_ERROR;
    }

    if (ngx_array_init(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers,
                       cf->pool, 1, sizeof(ngx_http_handler_pt))
        != NGX_OK)
    {
        return NGX_ERROR;
    }

    if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers,
                       cf->pool, 2, sizeof(ngx_http_handler_pt))
        != NGX_OK)
    {
        return NGX_ERROR;
    }

    if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers,
                       cf->pool, 4, 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;
}

可以看到

 NGX_HTTP_FIND_CONFIG_PHASE,  //根据uri替换location
 NGX_HTTP_POST_REWRITE_PHASE, //执行rewrite后处理
 NGX_HTTP_POST_ACCESS_PHASE,  //认证后处理, 认证不通过, 丢包
以上几个阶段都没有做数组的初始化化。

还要说一点的是,真正执行的时候,并不是调用cmcf->phases处理的, 而是调用cmcf->phase_engine.handlers
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) {

        rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);

        if (rc == NGX_OK) {  //只要return不为NGX_OK就继续执行。
            return;
        }
    }
}

phase_engine的初始化如下
static ngx_int_t
ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
{
    ngx_int_t                   j;
    ngx_uint_t                  i, n;
    ngx_uint_t                  find_config_index, use_rewrite, use_access;
    ngx_http_handler_pt        *h;
    ngx_http_phase_handler_t   *ph;
    ngx_http_phase_handler_pt   checker;

    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;
    }

    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;
            }
            checker = ngx_http_core_rewrite_phase;

            break;

        case NGX_HTTP_FIND_CONFIG_PHASE:
            find_config_index = n;

            ph->checker = ngx_http_core_find_config_phase;
            n++;
            ph++;

            continue;

        case NGX_HTTP_REWRITE_PHASE:
            if (cmcf->phase_engine.location_rewrite_index == (ngx_uint_t) -1) {
                cmcf->phase_engine.location_rewrite_index = n;
            }
            checker = ngx_http_core_rewrite_phase;

            break;

        case NGX_HTTP_POST_REWRITE_PHASE:
            if (use_rewrite) {
                ph->checker = ngx_http_core_post_rewrite_phase;
                ph->next = find_config_index;
                n++;
                ph++;
            }

            continue;

        case NGX_HTTP_ACCESS_PHASE:
            checker = ngx_http_core_access_phase;
            n++;
            break;

        case NGX_HTTP_POST_ACCESS_PHASE:
            if (use_access) {
                ph->checker = ngx_http_core_post_access_phase;
                ph->next = n;
                ph++;
            }

            continue;

        case NGX_HTTP_TRY_FILES_PHASE:
            if (cmcf->try_files) {
                ph->checker = ngx_http_core_try_files_phase;
                n++;
                ph++;
            }

            continue;

        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;

        for (j = cmcf->phases[i].handlers.nelts - 1; j >=0; j--) {
            ph->checker = checker;
            ph->handler = h[j];  //数组是反向赋值的,刚好对应了数组操作的顺序
            ph->next = n;        //next永远执行下一个阶段的执行索引
            ph++;
        }
    }

    return NGX_OK;
}

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

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

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

NGINX中HTTP请求的11个处理阶段

Nginx的模块化设计使得每一个HTTP模块可以仅专注于完成一个独立的、简单的功能,而一个请求的完整处理过程可以由无数个HTTP模块共同合作完成。这种设计有非常好的简单性、可测试性、可扩展性,然而,当...
  • lijinqi1987
  • lijinqi1987
  • 2016年11月03日 14:48
  • 2118

【Nginx】HTTP请求的11个处理阶段

Nginx将一个HTTP请求分成多个阶段,以模块为单位进行处理。这样做的好处是使处理过程更加灵活、降低耦合度。HTTP框架将处理分成了11个阶段,各个阶段以流水线的方式处理请求。这11个HTTP阶段如...
  • jy02326166
  • jy02326166
  • 2014年06月14日 21:41
  • 4540

nginx 处理请求原理和每个阶段的意思

适用 Nginx通过fastcgi调用python, Perl和C++等写的CGI程序。PHP有PHP-FPM (FastCGI Process Manager),这个对PHP来说更好的FastCG...
  • adparking
  • adparking
  • 2012年02月14日 14:35
  • 1620

文章13:Nginx多阶段处理HTTP请求

我自己添加的注释本文讲述了HTTP请求处理阶段的内容,非常棒的一篇文章。部分重点内容翻译如下,请大家阅读。 原文http://www.nginxguts.com/2011/01/phases/。...
  • yankai0219
  • yankai0219
  • 2012年10月13日 16:00
  • 6637

Nginx基础. HTTP多阶段处理大致分析

HTTP处理阶段的规则: 对于每个HTTP阶段, 它都包括checker检查方法和handler处理方法 typedef struct ngx_http_phase_handler_s ngx_h...
  • u012062760
  • u012062760
  • 2015年10月15日 19:32
  • 449

Nginx多阶段处理HTTP请求

原文博客地址:Nginx Guts Nginx服务器对HTTP请求的处理是分多个阶段的,每个阶段都有0个或者多个处理请求的函数会被调用。在Nginx源码中都有常量名称标志各个阶段。 下面是...
  • ciaos
  • ciaos
  • 2012年04月27日 14:24
  • 3090

《深入理解Nginx》笔记之 HTTP请求的11个处理阶段

HTTP请求的11个处理阶段typedef enum { // 接收到完整的HTTP头部后处理阶段 NGX_HTTP_POST_READ_PHASE = 0, // 将请求URI...
  • yzt33
  • yzt33
  • 2015年08月05日 09:19
  • 806

Nginx源码分析 - 实战篇 - 编写一个挂载到阶段处理的模块

HTTP模块篇,我们讲过Nginx的HTTP阶段处理 《Nginx源码分析 - HTTP模块篇 - ngx_http_core_run_phases函数和HTTP模块的阶段处理PHASE handle...
  • initphp
  • initphp
  • 2017年06月08日 13:19
  • 1345

nginx的多阶段请求处理

读取完请求头后,nginx进入请求的处理阶段。简单的情况下,客户端发送过的统一资源定位符(url)对应服务器上某一路径上的资源,web服务器需要做的仅仅是将url映射到本地文件系统的路径,然后读取相应...
  • fengmo_q
  • fengmo_q
  • 2013年02月21日 17:43
  • 12058

nginx源码分析--多阶段请求处理

读取完请求头后,nginx进入请求的处理阶段。简单的情况下,客户端发送过的统一资源定位符(url)对应服务器上某一路径上的资源,web服务器需要做的仅仅是将url映射到本地文件系统的路径,然后读取相应...
  • yusiguyuan
  • yusiguyuan
  • 2014年11月19日 21:05
  • 970
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:nginx的十一个阶段处理
举报原因:
原因补充:

(最多只允许输入30个字)