Nginx源码剖析--HTTP请求各阶段的具体作用


前言

Nginx将HTTP请求分为11各阶段进行处理。每个阶段包含零到多个handler处理函数。分阶段处理的目的是增加灵活性,方便模块介入。HTTP请求处理主要分为一下11个阶段:

typedef enum {
    NGX_HTTP_POST_READ_PHASE = 0,

    NGX_HTTP_SERVER_REWRITE_PHASE, //对server对应的uri的转换

    NGX_HTTP_FIND_CONFIG_PHASE, 
    NGX_HTTP_REWRITE_PHASE,       //locations对应的URI的转换
    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;

本文介绍一下各个阶段的一些具体的工作内容。

各个阶段的工作内容

  1. NGX_HTTP_POST_READ_PHASE

    这个阶段是在完整接收到HTTP请求之后的第一个处理阶段。目前Nginx的ngx_http_realip_module模块介入这个阶段,当然它是允许用户模块介入的。ngx_http_realip_module模块在postconfiguration函数中将它的ngx_http_realip_handler作为handler注入到流程当中。这个handler函数的主要作用是找到http请求的真是IP。具体可以参考HTTP请求的X-Forwarded-For头。

  2. NGX_HTTP_SERVER_REWRITE_PHASE

    这是重写阶段,重写http请求的URI。在Nginx里面,重写主要是通过指令完成。而且Nginx中重写指令可以在server块或者location块中出现。执行server块中的指令就是在这个阶段。执行location块的指令在NGX_HTTP_REWRITE_PHASE阶段。而指令的代码都是存储在rewrite模块的loc_conf配置结构体中。

  3. NGX_HTTP_FIND_CONFIG_PHASE

    这个阶段根据URL找到对应的匹配location块。后续的处理就可以用这个location块配置的模块来处理http请求。

  4. NGX_HTTP_REWRITE_PHASE

    这个阶段直接参考NGX_HTTP_SERVER_REWRITE_PHASE就可以了。 不过这里需要提一下的是,Nginx对这两个重写阶段的入口都是一样的,都是ngx_http_rewrite_handler,那是具体执行的时候是怎么区分这两个阶段的呢。其实不用区分,因为经过NGX_HTTP_FIND_CONFIG_PHASE和不经过NGX_HTTP_FIND_CONFIG_PHASE的请求对应的r->loc是不一样的。而r->loc数组中的rewrite模块对应的loc_conf中保存的就是具体的重写指令。可以看到,这是一种多态的实现。

  5. NGX_HTTP_POST_REWRITE_PHASE

    这是完成重写之后的一些收尾工作

  6. NGX_HTTP_PREACCESS_PHASE

    这是进入NGX_HTTP_ACCESS_PHASE阶段前的应该完成的工作

  7. NGX_HTTP_ACCESS_PHASE

    这个阶段主要是做一些访问权限相关的处理。

  8. NGX_HTTP_POST_ACCESS_PHASE

    NGX_HTTP_ACCESS_PHASE阶段之后的的工作在这里完成

  9. NGX_HTTP_TRY_FILES_PHASE

    顺序访问多个静态文件资源阶段

  10. NGX_HTTP_CONTENT_PHASE

    这个阶段一般是处理http请求的内容。另外需要说一下的是,这个阶段有两种介入方式:

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

// 下面是后一种介入方式
    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "content phase: %ui", r->phase_handler);

    rc = ph->handler(r);

    if (rc != NGX_DECLINED) {
        ngx_http_finalize_request(r, rc);
        return NGX_OK;
    }
  1. NGX_HTTP_LOG_PHASE

    日志阶段

http请求处理阶段的介入方式

一般是模块在它的postconfiguration函数中介入。介入方式就是将handler函数加入到ngx_http_core_module模块的main_conf的phases数组中,因为后面主要是根据这个数组初始化phase_engine.handlers。具体地可以参考下面这段代码:

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

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

ngx_http_rewrite_init是rewrite模块的postconfiguration函数。

总结

这篇文章主要介绍了http请求处理过程中,各个阶段完成的工作。最后介绍了一下模块是如何将handler介入到各个阶段的。

猜你喜欢

转载自blog.csdn.net/swartz2015/article/details/78635764