在nginx中,如果你要开发一个过滤模块,config中必须要加
HTTP_FILTER_MODULES=$HTTP_FILTER_MODULES xxx
否则,即使在postconfiguration回调中加了ngx_http_top_header_filter=my_xxxx_filter_handle,最终my_xxxx_filter_handle也不会调用。这是如何做到的呢?
搜索HTTP_FILTER_MODULES,这个变量似乎没做什么事,就是保存了过滤模块而已。
我们知道只要加了HTTP_MODULES=$HTTP_MODULES xxx即可,我们的模块就生效了,而且postconfiguration也会被调用,在回调中设置了回调的链表。最终未被调用,其秘密就藏在了auto/modules这个脚本中
在其中搜索HTTP_FILTER_MODULES,可以看到:
这上面有段注释,说明了,过滤模块的顺序很重要,再往上则是说http模块顺序也很重要。
因此在HTTP_FILTER_MODULES下面有个ngx_module_order对模块进行了排序,这个决定了模块最终在全局变量ngx_modules数组中顺序位置。但是这里有个疑惑,这只是决定了模块在数组中的位置而已,他是如何决定config中加了HTTP_FILTER_MODULES变量后,过滤回调才能被调用的呢?
即,加了HTTP_FILTER_MODULES,你的过滤回调才能被调用,否则不可能。
以header_filter为例,
首先这个顺序是最重要,但是他是如何做到的呢?
答案就在ngx_http_header_filter_module这个模块中,
ngx_http_header_filter_module,是第一个被初始化的过滤模块
我们看其初始化函数:
static ngx_int_t
ngx_http_header_filter_init(ngx_conf_t *cf)
{
ngx_http_top_header_filter = ngx_http_header_filter;
return NGX_OK;
}
在这里,最先初始化ngx_http_top_header_filter,之后的模块则都是
xxx_next_header_filter=ngx_http_top_header_filter;
ngx_http_top_header_filter=xxx_header_filter;
依次来形成了回调链表。
如果我们的模块不是HTTP_FILTER_MODULES,那么我们的模块则一定排在ngx_http_header_filter_module之前,因此我们的模块被先初始化,即使我们挂了回调,那么等到调用ngx_http_header_filter_module模块初始化的时,直接重置了ngx_http_top_header_filter,使先前的链表直接失效了。这个排序在configiure执行后,可以在objs/ngx_modules.c可以看到。
nginx这样的设计是比较巧妙,如果你不显示告诉configure你是HTTP_FILTER_MODULES,那么最终程序中你的过滤回调就不会生效。