543: 552: 582: 586: 590: 618: 632: 633: |
659: 691: 712: 729: 745: 746: 747: 748: 785: 786: |
ngx_http_script_var_code |
ngx_http_script_value_code |
ngx_http_script_equal_code |
ngx_http_script_if_code |
ngx_http_script_var_code |
ngx_http_script_regex_start_code |
ngx_http_script_if_code |
ngx_http_script_complex_value_code |
ngx_http_script_file_code |
ngx_http_script_if_code |
1.3.
条件类型
内部指令集
备注
变量等式
ngx_http_script_var_code
值拷贝根据是否含变量分为两类
值拷贝
ngx_http_script_value_code
ngx_http_script_complex_value_code
ngx_http_script_equal_code
变量不等式
ngx_http_script_var_code
值拷贝根据是否含变量分为两类
值拷贝
ngx_http_script_value_code
ngx_http_script_complex_value_code
ngx_http_script_not_equal_code
变量正则表达式
ngx_http_script_var_code
ngx_http_script_regex_start_code
文件检测
值拷贝
ngx_http_script_value_code
值拷贝根据是否含变量分为两类
ngx_http_script_complex_value_code
ngx_http_script_file_code
if条件后面是一个块。我们前面说了,这个块中的指令类型可能是NGX_HTTP_SIF_CONF或者NGX_HTTP_LIF_CONF。我们现在来看一下,究竟有哪些指令属于这个范畴。我们不具体列出这些指令,因为nginx发展过程中,这些指令肯定会发生变量,我们这里只看他们的特点。
所有指令分为两类:
l
l
if指令和其他rewrite模块指令一样,都是在处理请求的时候,在REWRITE_PHASE时被处理。处理函数是ngx_http_rewrite_handler。其核心
由此可见,nginx的指令执行的核心其实是各个内部指令的实现本身。接下来,我们就一起来分析if涉及到的这些内部指令。
2.1.
nginx内部指令和CPU指令有点类似:op和操作数。我们刚刚看到的ngx_http_script_var_code等等就是op,其实就是个函数指针。每个op都有不同数量和类型的操作数。这些操作数和op一起放在各个不同的数据结构中,比如ngx_http_script_var_code对应的数据结构就是ngx_http_script_var_code_t。每个内部指令的整个数据结构都完整的放在nginx的内部指令序列中,就和C代码段中既有op,又有直接操作数一样。那么nginx如何识别指令呢?那就是所有数据结构的第一个属性都必须是op回调函数指针。这样一来,nginx通过ip指针指向内部指令序列的某一个地址,那个地址一定是op回调函数指针。在op回调函数,ip指针被修改,移到下一条指令的开始处,那么此地址也是下一条指令的op回调函数指针。
2.2.
取得变量,*e->sp = *value; e->sp++;
这里有个问题,sp是什么?nginx内部指令处理过程中,ip指向内部指令序列,sp指向结果序列。看到sp,大家其实很容易联想到堆栈,nginx的sp实现确实像个堆栈,有压栈也有出栈。
2.3.
核心代码是
1660:
1661:
1666:
这个很简单,就是字符串赋值。
2.4.
这个过程稍微复杂一点,但是原理还是一样的,可以看这段代码
甭管值是如何得到的,过程是一样的。在这里,值是通过执行另一段内部指令序列得到的,这里不作展开。
1645:
1646:
1647:
2.5.
因为存值的时候sp都加了1,所以判断相等时sp先减1,。接着取出比较的两个值val和res。注意比较的结果存放在res中,这个过程中sp的示意图是:
1426:
1427:
1428:
1432:
1433:
1434:
1435:
1436:
1437:
1439:
before:
after:
2.6.
它和ngx_http_script_equal_code流程完全相同,逻辑完全相反,不做赘述。
2.7.
ngx_http_script_regex_start_code在多种条件下使用,所以逻辑很杂。和if相关的流程如下:
正则表达式的处理和前面的等式以及不等式有些区别,不知道大家发现了没有?操作数的处理不同。后两者的操作数都是通过别的内部指令提前存放在结果序列中的,而正则表达式只有一个参数在结果序列中,另外一个参数在指令数据结构中保存引用。为什么需要这样呢?因为“~”后面的字符串只有在前面是正则运算符的时候才有意义,所以这个字符串就在处理正则运算符的时候连带处理掉了。处理过程前面已经遇到过,大家可以再回顾一下。
931:
932:
933:
936:
938:
947:
…
965:
978:
…
992:
2.8.
内部指令ngx_http_script_file_code从sp取得文件名,接着调用ngx_open_cached_file()函数测试文件,最后根据测试结果将真或假存回sp。
2.9.
内部指令ngx_http_script_if_code很显著的特点是一个消费者,它从sp中取出数据,判断值是否为真,但是不产生新的值。我们前面提到过if条件为真时的处理逻辑。看到
分析这段代码可以得出if条件为真时的工作过程是使用if中的loc_conf替换请求loc_conf
e->request->loc_cOnf=
code->loc_conf;,更新请求参数,然后执行后面的内部指令e->ip += sizeof(ngx_http_script_if_code_t);。如果条件非真,则直接跳过解析if块中的指令得到的内部指令序列e->ip
+= code->next;。
1401:
1402:
1403:
1404:
1405:
1407:
1408:
1409:
1415:
代码中明显更新的是e->request,为什么说更新的是r->request呢?因为在ngx_http_rewrite_handler()中有e->request
= r;。
至于nginx是如何通过location配置更新请求参数的,这个问题不在本文讨论范围内。
本文分析了nginx处理if条件的流程,见识了nginx内部指令的。虽然说并不是完全了解了nginx的脚本机制,但也不仅仅只是豹窥一斑的肤浅程度。
了解了这些有什么用呢?
稍微复杂点的条件写成nginx配置,怎得一个蛋疼可以形容。了解了这块的逻辑,搞个and\or\not难道是一个怎么复杂的事情?
有if没有else,没有这个比没有and\or可能更麻烦。不过这个不那么容易做,但也不是不能做。