您的位置:首页 > 理论基础 > 计算机网络

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

2016-11-03 14:48 721 查看
Nginx的模块化设计使得每一个HTTP模块可以仅专注于完成一个独立的、简单的功能,而一个请求的完整处理过程可以由无数个HTTP模块共同合作完成。这种设计有非常好的简单性、可测试性、可扩展性,然而,当多个http模块流水式地处理同一个请求时,单一的处理顺序是无法满足灵活性需求的,每一个正在处理的HTTP模块很难灵活、有效地指定下一个HTTP处理模块是哪一个。
因此,HTTP框架依据常见的处理流程将处理阶段划分为11个阶段,其中每个处理阶段都可以由任意多个HTTP模块流水式地处理请求。

typedef enum {
//在接收到完整的HTTP头部后处理的HTTP阶段
NGX_HTTP_POST_READ_PHASE = 0,

//在请求的URI与location表达式匹配前,修改请求的URI(重定向),是一个独立的HTTP阶段
NGX_HTTP_SERVER_REWRITE_PHASE,

//根据请求的URI寻找匹配的location表达式,这个阶段只能由
NGX_HTTP_FIND_CONFIG_PHASE,

//在NGX_HTTP_FIND_CONFIG_PHASE阶段寻找到匹配的location之后再修改请求的URI
NGX_HTTP_REWRITE_PHASE,

//这一阶段是用于在rewrite重写URL后,防止错误的nginx.conf配置导致死循环(递归地修改URI)
NGX_HTTP_POST_REWRITE_PHASE,

//表示在处理NGX_HTTP_ACCESS_PHASE阶段觉得请求的访问权限前,HTTP模块可以介入的处理阶段
NGX_HTTP_PREACCESS_PHASE,

//这个阶段用于让HTTP模块判断是否允许这个请求访问nginx服务器
NGX_HTTP_ACCESS_PHASE,

//在NGX_HTTP_ACCESS_PHASE阶段中,当HTTP模块的handler处理函数返回不允许访问的错误码时(NGX_HTTP_FORBIDDEN或者NGX_HTTP_UNAUHORIZED),这里将负责向用户发送拒绝服务的错误响应。
NGX_HTTP_POST_ACCESS_PHASE,

//此阶段专门为try_files配置项设立,当HTTP请求访问静态文件资源时,try_files配置项可以使这个配置项顺序地访问多个静态文件资源
NGX_HTTP_TRY_FILES_PHASE,

//用于处理HTTP请求内容的阶段,这是大部分HTTP模块最愿意介入的阶段
NGX_HTTP_CONTENT_PHASE,

//处理完请求后记录日志的阶段,ngx_http_log_module模块就在这个阶段中加入了一个handler处理方法,使得每个HTTP请求处理完毕后会记录access_log访问日志
NGX_HTTP_LOG_PHASE
} ngx_http_phases;


这11个阶段有些是必备的,有些是可选的,也可以有多个HTTP模块同时介入同一阶段
 
HTTP阶段的定义,包括checker检查方法和handler处理方法,如下所示:

typedef structngx_http_phase_handler_s ngx_http_phase_handler_t;

/*一个HTTP处理阶段中的checker检查方法,仅可以由HTTP框架实现,以此控制HTTP请求的处理流程*/
typedef ngx_int_t(*ngx_http_phase_handler_pt)(ngx_http_request_t *r, ngx_http_phase_handler_t*ph);

/*由HTTP模块实现的handler处理方法*/
typedef ngx_int_t(*ngx_http_handler_pt)(ngx_http_request_t *r);

struct ngx_http_phase_handler_s {
/*在处理到某一个HTTP阶段时,HTTP框架将会在checker方法已实现的前提下首先调用checker方法来处理请求,
而不会直接调用任何阶段中的hanlder方法,只有在checker方法中才会去调用handler方法,因此,事实上所有
的checker方法都是由框架中的ngx_http_core_module模块实现的,且普通模块无法重定义checker方法*/
ngx_http_phase_handler_pt  checker;

/*除ngx_http_core_module模块以外的HTTP模块,只能通过定义handler方法才能介入某一个HTTP处理阶段以处理请求*/
ngx_http_handler_pt        handler;

/*将要处理的下一个HTTP处理阶段的序号
next的设计使得处理阶段不必按顺序依次执行,既可以向后跳跃数个阶段继续执行,也可以跳跃到之前的某个阶段重新
执行,通常,next表示下一个处理阶段中的第1个ngx_http_phase_handler_t处理方法*/
ngx_uint_t                 next;
};


一个http{}块解析完毕后,将会根据nginx.conf中的配置产生由ngx_http_phase_handler_t组成的数组,在处理HTTP请求时,一般情况下这些阶段是顺序向后执行的,但ngx_http_phase_handler_t中的next成员使得它们也可以非顺序地执行,ngx_http_phase_engine_t结构体就是所有ngx_http_phase_handler_t组成的数组,如下所示:

typedef struct {
/*handlers是由ngx_http_phase_handler_t构成的数组首地址,它表示一个请求可能经历的所有ngx_http_handler_pt处理方法*/
ngx_http_phase_handler_t  *handlers;

/*表示NGX_HTTP_SERVER_REWRITE_PHASE阶段第1个ngx_http_phase_handler_t处理方法在handlers数组中的序号,用于在执行
HTTP请求的任何阶段中快速跳转到HTTP_SERVER_REWRITE_PHASE阶段处理请求*/
ngx_uint_t                 server_rewrite_index;

/*表示NGX_HTTP_PREACCESS_PHASE阶段第1个ngx_http_phase_handler_t处理方法在handlers数组中的序号,用于在执行
HTTP请求的任何阶段中快速跳转到NGX_HTTP_PREACCESS_PHASE阶段处理请求*/
ngx_uint_t                 location_rewrite_index;
} ngx_http_phase_engine_t;


可以看到,ngx_http_phase_engine_t中保存了在当前nginx.conf配置下,一个用户请求可能经历的所有ngx_http_handler_pt处理方法,这是所有HTTP模块可以合作处理用户请求的关键,这个ngx_http_phase_engine_t结构体保存在全局的ngx_http_core_main_conf_t结构体中,如下:
typedef struct {
ngx_array_t servers; /* ngx_http_core_srv_conf_t */
/*由下面各阶段处理方法构成的phases数组构建的阶段引擎才是流水式处理HTTP请求的实际数据结构*/
ngx_http_phase_engine_t phase_engine;
ngx_hash_t headers_in_hash;
ngx_hash_t variables_hash;
ngx_array_t variables; /* ngx_http_variable_t */
ngx_uint_t ncaptures;
ngx_uint_t server_names_hash_max_size;
ngx_uint_t server_names_hash_bucket_size;
ngx_uint_t variables_hash_max_size;
ngx_uint_t variables_hash_bucket_size;
ngx_hash_keys_arrays_t *variables_keys;
ngx_array_t *ports;
ngx_uint_t try_files; /* unsigned try_files:1 */
/*用于在HTTP框架初始化时帮助各个HTTP模块在任意阶段中添加HTTP处理方法,它是一个有11个成员的ngx_http_phase_t数组,
其中每一个ngx_http_phase_t结构体对应一个HTTP阶段,在HTTP框架初始化完毕后,运行过程中的phases数组是无用的*/
ngx_http_phase_t phases[NGX_HTTP_LOG_PHASE + 1];
} ngx_http_core_main_conf_t;

在ngx_http_phase_t中关于HTTP阶段有两个成员:phase_engine和phases,其中phase_engine控制运行过程中的一个HTTP请求所要经过的HTTP处理阶段,它将配合ngx_http_request_t结构体中的phase_handler成员使用(phase_handler制定了当前请求应当执行哪一个HTTP阶段);而phases数组更像一个临时变量,它实际上仅会在Nginx启动过程中用到,它的唯一使命是按照11个阶段的概率初始化phase_engine中的handlers数组

typedef struct {
/*handlers动态数组保存着每一个HTTP模块初始化时添加到当前阶段的处理方法*/
ngx_array_t                handlers;
} ngx_http_phase_t;



在HTTP框架的初始化过程中,任何HTTP模块都可以在ngx_http_module_t接口的postconfiguration方法中将自定义的方法添加到handler动态数组中,这样,这个方法就会最终添加到phase_engine动态数组中。
 
 
 
 
参考:《深入理解Nginx模块开发与架构设计》 陶辉  机械工业出版社
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: