当同一个location配置块使用了多个nginx模块的配置指令时,这些指令的执行顺序很可能会跟它们的书写顺序大相径庭。于是许多人选择了“试错法”,然后它们的配置文件就时常被改得一片狼藉。这个系列的教程就是为了帮助读者逐步地理解配置指令背后的执行时间和先后顺序的奥秘。
现在来看看这样一个令人困惑的例子:
?location /test {
? set $a 32;
? echo $a;
?
? set $a 56;
? echo $a;
?}
这个例子的本意来看,我们期望的输出行时一行32和一行56,因为我们第一次用echo配置指令输出了$a 变量以后,又紧接着使用了set配置指令修改了$a.然而不幸的是,事实并非如此:
$curl 'http://localhost:8080/test
56
56
我们看到,语句set$ a 56似乎在第一条echo$a 语句之前执行过了。着究竟是为什么呢?
显然,这里并没有nginx的bug;要理解这里发生的事情,就首先要知道nignx处理每一个用户的请求时,都是按照若干不同阶段(phase)处理的。
nginx的请i去处理阶段共有11歌之多,我们先介绍其中三种比较常见的。按照它们执行的先后顺序,依次是rewrite阶段、access阶段以及content阶段(后面我们还有机会见到其他的更多处理阶段).
所有nginx模块提供的配置指令一般只会注册并运行在其中的某一个处理阶段。比如上例中的set指令就是在rewrite阶段运行的,而echo指令就只会在content阶段的配置指令之前执行,因此属于rewrite阶段配置指令也总是会无条件地在content阶段的配置指令之前执行。于是在同一个location配置块中,set指令总是会echo指令之前执行,即使我们在配置文件中有意的把set语句写在echo语句的后面。
回到刚才那个例子,
set $a 32
echo $a;
set $a 56;
echo $a;
实际的执行顺序应当是
set $s 32;
set $a 56;
echo $s;
echo $a;
即使rewrite阶段执行玩的这里两条set赋值语句,然后再在后面的content阶段依次执行那两条echo指令。分属两个不同处理阶段的配置指令之间是不能穿插着运行的。
为了进一步验证这一点,我们不妨借助ngixn的“调试日志”来一窥nignx 的实际执行过程。
因为这个是我们第一次提及nginx的“调试日志”,所以有必要介绍一下它的启用方法。“调试日志”默认是禁用的,因为它会引入比较大的运行时的开销,让nginx 服务器显著变慢。一般我们需要重新编译和构造nginx可执行文件,并且在调用nginx源码包提供的 ./configure 脚本时传入--with-debug命令行选项。例如我们下载完nginx源码包后在linux后者mac os 等系统构造时,典型的步骤时这样的:
tar xvf nginx-1.0.10,tar.gz
cd nginx-1.0.10/
./configure --with-debug
make
sudo make install
当我们启用--with-debug选项重新构建好调试版的nginx之后,还需要同时在配置文件中通过标准的error-log配置指令为错误日志使用debug日志级别(这同时时最低的日志级别)