概述
在前面的文章,我们知道当Nginx获取到连接后,会首先对连接的请求进行处理,例如读取请求的uri,参数等,然后会调用ngx_http_core_run_phases函数对于该请求跑一遍phase,当所有的phase都跑完了以后,那么这个请求也就处理完成了。
好,我们首先来看一下Nginx的phase的定义吧:
//Nginx定义的11个phase
typedef enum {
NGX_HTTP_POST_READ_PHASE = 0, //读取请求的phase
NGX_HTTP_SERVER_REWRITE_PHASE, //这个阶段主要是处理全局的(server block)的rewrite
NGX_HTTP_FIND_CONFIG_PHASE, /* 根据uri查找location */
NGX_HTTP_REWRITE_PHASE, /* localtion级别的rewrite */
NGX_HTTP_POST_REWRITE_PHASE, /* server、location级别的rewrite都是在这个phase进行收尾工作的 */
NGX_HTTP_PREACCESS_PHASE, /* 粗粒度的access */
NGX_HTTP_ACCESS_PHASE, /* 细粒度的access,比如权限验证、存取控制 */
NGX_HTTP_POST_ACCESS_PHASE, /* 根据上述两个phase得到access code进行操作 */
NGX_HTTP_TRY_FILES_PHASE, /* 实现try_files指令 */
NGX_HTTP_CONTENT_PHASE, /* 生成http响应 */
NGX_HTTP_LOG_PHASE /* log模块 */
} ngx_http_phases;
然后我们在ngx_http_core_main_conf_t结构中可以看到如下的定义:
/**
* 所有的phase的数组,其中每个元素是该phase上注册的handler的数组。
*/
ngx_http_phase_t phases[NGX_HTTP_LOG_PHASE + 1];
phases静态数组保存了所有的http类型的模块定义的phase处理函数,这里我们看一下ngx_http_phase_t结构:
//phase的定义
typedef struct {
ngx_array_t handlers; //处理函数
} ngx_http_phase_t;
其实说白了每一个phase就对应一个数组,用来保存该phase的所有处理函数。我们首先来看phases数组的是如何初始化的,在http命令的回调函数ngx_http_block中我们可以看到如下代码:
if (ngx_http_init_phases(cf, cmcf) != NGX_OK) { //因为nginx把http分化成为11个phase,每一个phase都可以注册handler,ngx_http_core_main_conf_t里面的phases所有的phase handler数组,ngx_http_init_phases函数完成每一个phase的handler的初始化
return NGX_CONF_ERROR;
}
调用了ngx_http_init_phases函数来初始化phases数组。该函数其实很简单,因为phases数组中每一个元素都有一个数组用来保存该phase的处理函数,
ngx_http_init_phases函数就是调用ngx_array_init来初始化这些数组的。
嗯,接下来我们来看一下在ngx_http_core_main_conf_t中的另外一个比较重要的域:
/**
* 包含所有phase,以及注册的phase handler,这些handler在处理http请求时,
* 会被依次调用,通过ngx_http_phase_handler_t的next字段串联起来组成一个
* 链表。
*/
ngx_http_phase_engine_t phase_engine;
这个域将会包含一个动态数组,用来存储所有的phase的handler,并且将它们组成类似于链表的方式,这样额可以方便以后phase按照顺寻来调用。我们首先来看看ngx_http_phase_engine_t结构的定义吧:
typedef struct {
ngx_http_phase_handler_t *handlers; //它是一个动态数组,用来保存所有的ngx_http_phase_handler_t结构
/**
* server rewrite阶段的handler在ngx_http_core_main_conf_t->phase_engine.handlers数组中的下标
*/
ngx_uint_t server_rewrite_index;
/**
* rewrite阶段的handler在ngx_http_core_main_conf_t->phase_engine.handlers数组中的下标
*/
ngx_uint_t location_rewrite_index;
} ngx_http_phase_engine_t;
handler域是一个动态数组,它将会用来保存所有phase的handler,但是这里保存的元素稍微变了一下,并不是单纯的函数了,而是一个ngx_http_phase_handler_t结构,接下来我们来看看这个结构的定义:
struct ngx_http_phase_handler_s {
ngx_http_phase_handler_pt checker; //当前handler的checker函数,同一phase的所有handlerchecker都是统一的
ngx_http_handler_pt handler; //处理函数
ngx_uint_t next; //下一个phase的第一个handler在phase_engine的handlers数组中的下标,用这种方式将phase链成了一个链表,可以用来按照phase的顺序来调用handler
};
这里checker函数在同一个phase的所有handler里都是一样的,而且最终handler函数的调用也是在checker函数中完成的,handler就是对应的函数,next是下一个phase的第一个handler在phase_engine的handlers数组中下表,nginx就是利用这种方式将phase变成了类似于链表的结构,方便调用。
嗯,接下来我们来看一下phase_engine的初始化,在http命令回调函数中会找到如下代码:
if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) { //初始化phase_engine
return NGX_CONF_ERROR;
}
调用了ngx_http_init_phase_handlers函数来初始化
phase_engine,好了,接下来我们来看看ngx_http_init_phase_handlers函数吧:
//将ngx_http_core_main_conf_t的phases数组中的handler信息转化为ngx_http_phase_handler_t结构,并将他们保存在phase_engine.handlers数组中
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;d
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; /* ngx_http_rewrite在http module的postconfiguration回调函数中添加REWRITE阶段的处理函数 */
use_access = cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0; /* ngx_http_access在http module的postconfiguration回调函数中添加ACCESS阶段的处理函数 */
//n用来统计所有的phase 的handler的数量
n = use_rewrite + use_access + cmcf->try_files + 1 /* find config phase */;
for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) { //遍历phase数组中的所有的phase,然后将它们handler的数量加起来
n += cmcf->phases[i].handlers.nelts;
}
//嗯,这里还加了一个空指针
ph = ngx_pcalloc(cf->pool,
n * sizeof(ngx_http_phase_handler_t) + sizeof(void *)); //这里说白了是为phase_engine.handlers动态数组分配内存空间,因为最后phase_engine.handlers会指向ph,用来保存所有的ngx_http_phase_handler_t
if (ph == NULL) {
return NGX_ERROR;
}
cmcf->phase_engine.handlers = ph; //将phase_engine.handlers指向刚刚的ph
n = 0;
/*
* 初始化phase handler,保存checker和next字段
* continue的都是不能添加handler的phase
*/
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; //记住NGX_HTTP_SERVER_REWRITE_PHASE的第一phase的handler的下标
}
checker = ngx_http_core_rewrite_phase; //NGX_HTTP_SERVER_REWRITE_PHASE的checker
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; //记住NGX_HTTP_REWRITE_PHASE第一个handler的下标
}
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; //它的next比较怪,指向前面的,这里主要是为了处理uri重写的情况
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; //其余phase的checker函数是ngx_http_core_generic_phase
}
n += cmcf->phases[i].handlers.nelts; //这里n将表示下一个phase开始的第一个handler的在phase_engine.handlers数组中的下标
for (j = cmcf->phases[i].handlers.nelts - 1; j >=0; j--) {
ph->checker = checker; //为当前ngx_http_phase_handler_t的checker函数赋值,在同一个phase中,checker是统一的,handler不一样
ph->handler = h[j]; //为handler赋值
ph->next = n; // 指向下一个phase的第一个handler,nginx用这种方式将他们串成了一个链
ph++;
}
}
return NGX_OK;
}
其实该函数还是很简单的,基本上上面的注释都已经说的很清楚了。而且能够很明白nginx是如何将phase的handler组织成为类似于链表的机构方便phase的顺序调用,而且可以知道同一个phase中,其checker函数都是一样的。不过这里有个地方需要注意,就是NGX_HTTP_POST_REWRITE_PHASE部分的下一个phase指向的是NGX_HTTP_FIND_CONFIG_PHASE,这里可能是因为需要一些额外的处理吧。另外可以知道有的phase是只有一个handler的,例如
NGX_HTTP_POST_REWRITE_PHASE,有的phase则可以有很多handler。
好了,phase的初始化就讲的差不多了,下一篇文章讲讲是如何调用这些phase来处理http请求的吧。
最后
以上就是积极小兔子为你收集整理的Nginx的phase初始化的全部内容,希望文章能够帮你解决Nginx的phase初始化所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复