6.2.2 过滤链表的顺序

HTTP过滤模块之间的调用顺序是非常重要的。如果两个HTTP过滤模块按照相反的顺序执行,完全可能生成两个不同的HTTP响应包。例如,如果现在有一个图片缩略图过滤模块,还有一个图片裁剪过滤模块,当返回一张图片给用户时,这两个模块的执行顺序不同的话就会导致用户接收到不一样的图片。

在上文中提到过,Nginx在编译过程中就会决定HTTP过滤模块的顺序。这件事情到底是怎样发生的呢?这其实与3.3节中所说的普通HTTP模块的顺序是一样的,也是由configure生成的ngx_modules数组中各模块的顺序决定的。

由于每个HTTP过滤模块的初始化方法都会把自己加入到单链表的首部,所以,什么时候、以何种顺序调用这些HTTP过滤模块的初始化方法,将会决定这些HTTP过滤模块在单链表中的位置。

什么时候开始调用各个HTTP模块的初始化方法呢?这主要取决于我们把类似ngx_http_myfilter_init这样的初始化方法放到ngx_http_module_t结构体的哪个回调方法成员中。例如,大多数官方HTTP过滤模块都会把初始化方法放到postconfiguration指针中,那么它就会在图4-1的第6步将当前模块加入到过滤链表中。不建议把初始化方法放到ngx_http_module_t的其他成员中,那样会导致HTTP过滤模块的顺序不可控。

初始化时的顺序又是如何决定的呢?首先回顾一下第1章的相关内容,在1.7节中,介绍了configure命令生成的ngx_modules.c文件,这个文件中的ngx_modules数组会保存所有的Nginx模块,包括HTTP普通模块和HTTP过滤模块,而初始化Nginx模块的顺序就是ngx_modules数组成员的顺序。因此,只需要查看configure命令生成的ngx_modules.c文件就可以知道所有HTTP过滤模块的顺序了。

由此可知,HTTP过滤模块的顺序是由configure命令生成的。当然,如果用户对configure命令生成的模块顺序不满意,完全可以在configure命令执行后、make编译命令执行前修改ngx_modules.c文件的内容,对ngx_modules数组中的成员进行顺序上的调整。

注意 对于HTTP过滤模块来说,在ngx_modules数组中的位置越靠后,在实际执行请求时就越优先执行。因为在初始化HTTP过滤模块时,每一个http过滤模块都是将自己插入到整个单链表的首部的。

configure执行时是怎样确定Nginx模块间的顺序的呢?当我们下载官方提供的Nginx源代码包时,官方提供的HTTP过滤模块顺序已经写在auto目录下的modules脚本中了。图6-1描述了这个顺序。

如果在执行configure命令时使用—add-module选项新加入第三方的HTTP过滤模块,那么第三方过滤模块会处于ngx_modules数组中的哪个位置呢?答案也可以在图6-1中找到。

6.2.2 过滤链表的顺序 - 图1

图 6-1 默认即编译进Nginx的官方HTTP过滤模块与第三方HTTP过滤模块间的顺序

如图6-1所示,在执行configure命令时仅使用—add-module参数添加了第三方HTTP过滤模块。这里没有把默认未编译进Nginx的官方HTTP过滤模块考虑进去。这样,在configure执行完毕后,Nginx各HTTP过滤模块的执行顺序就确定了。默认HTTP过滤模块间的顺序必须如图6-1所示,因为它们是“写死”在auto/modules脚本中的。读者可以通过阅读这个modules脚本的源代码了解Nginx是如何根据各官方过滤模块功能的不同来决定它们的顺序的。对于图6-1中所列的这些过滤模块,将在下面进行简单的介绍。