nginx脚本引擎与设计设计(三)

来源:互联网 发布:oracle rac windows 编辑:程序博客网 时间:2024/04/29 06:57


        这一部分我们将探讨一些较细节的东西,加上前面(一),(二)两篇文章对典型情景的分析,我相信应该会对大家理解nginx的脚本解析机制有很大的帮助的。

 

        这里我们关注ngx_http_core_main_conf_t(下面简写为cmcf)结构中的这两个成员,cmcf->variables_keys和cmcf->variables,其中variables_keys是个hash数组,变量hash值相同的放到一个数组中,而且是唯一的,重复时会报错。重要的是这个hash数组,即cmcf->variables_keys,保存了整个系统中所有预定义的,自定义,几乎所有的变量(一些特定前缀的变量除外,如“http_”等,在函数ngx_http_variables_init_vars中都列出来了)。

 

我们分条目来看:

1.  系统中所有可能用到变量都会放到cmcf->variables_keys中。

 

2.  配置中出现的变量(在处理请求时会用到的),会放到cmcf->variables中。总体上来看,除去一些有特定前缀的变量(这类变量后面会讲),cmcf->variables可以看做是ngx_http_variables_init_vars的子集。从这里的设计可以看出来,系统定义的变量在请求处理时,并不会全部用到,我们只需根据配置,拿到有用的就可以了,所以cmcf->variables_keys使用了temp_pool(实际的元素则使用cf->pool),当variables收集变量完成之后,variables_keys结构也就没什么用处了。

 

3.  cmcf->variables是一个数组,它的元素类型为ngx_http_variable_t。

struct ngx_http_variable_s {   // 变量名字符串    ngx_str_t                    name; // 使用变量中的值设置request的某个成员的值,所谓set    ngx_http_set_variable_pt   set_handler;// 根据request中成员(如uri,args等)的值来设置,r->variables中对应变量的内容。     ngx_http_get_variable_pt   get_handler;// 需要具体处理的具体内容,因为这个结构是通用的,那么具体处理的信息就放到// data成员中    uintptr_t                    data;// 一些标识信息,区别不同处理,后面会详细讲    ngx_uint_t                   flags;// 该变量在cmcf->variables数组中的下标    ngx_uint_t                   index;};

4.  在init_request阶段,我们看到有这样的处理:

r->variables =ngx_pcalloc(r->pool, cmcf->variables.nelts * sizeof(ngx_http_variable_value_t));

这里的设计思想是这样的,cmcf->variables是每个变量的处理信息的封装,而r-> variables里面则是处理该变量得到的内容(即value),所以cmcf->variables跟r->variables是一一对应的,成员之间就是var对value的关系,这不过这里的var和value是封装了很多信息的结构,不是单纯的值或字符串。这里我们看下r->variables的成员。

typedef struct {    unsigned    len:28;    unsigned    valid:1;          // 表示该变量在数组中并且有效,可以使用// 表示使用该变量时,需要重新通过get_handler来获取,因为该变量的实际内容// 可能已经改变了。    unsigned    no_cacheable:1; // 特定位置上的变量不存在(实际上是没有设置),那么它就是“not found”!    unsigned    not_found:1;    unsigned    escape:1; // 这里不管它,跟我们的情景没有多大关系    u_char     *data;} ngx_variable_value_t;

 

我们看到这个结构中处理包含代表直接变量值的指针和大小(即data和len)外,剩下的都是一些标记位。

 

下面我们看几个宏:

#define NGX_HTTP_VAR_CHANGEABLE   1

#define NGX_HTTP_VAR_NOCACHEABLE  2

#define NGX_HTTP_VAR_INDEXED       4

#define NGX_HTTP_VAR_NOHASH        8

 

1.  NGX_HTTP_VAR_CHANGEABLE

使用这个宏的时候意味着,该变量可以重复配置,一般后配置的会覆盖前面的配置。如:

set $file $1

set $file $2

那么结果就是file的最终值就是$2所代表的。

2.  NGX_HTTP_VAR_NOCACHEABLE

这个宏所影响的正是ngx_variable_value_t结构中的no_cacheable,前面注释里面提到过,凡是有该标记的变量,都要通过get_handler来获取变量的值。如下面函数:

ngx_http_get_flushed_variable(ngx_http_request_t *r, ngx_uint_tindex){   ngx_http_variable_value_t  *v;   v = &r->variables[index];// 找到变量,发现是有效的,但是由于属于NGX_HTTP_VAR_NOCACHEABLE,所以// 需要在cmcf->variables找到它的处理结构来重新获取新值。   if (v->valid) {  // 变量有效,具备可以使用的潜质       if (!v->no_cacheable) { //可以直接用,就返回了            return v;       }       // 这是一个NGX_HTTP_VAR_NOCACHEABLE类型的变量,那么…       v->valid = 0;       v->not_found = 0;   }// 重新获取,这个函数就不看了,大家可以自己分析   returnngx_http_get_indexed_variable(r, index);}

 

这种变量往往是跟特定的请求紧密相关的,如host,uri,args之类的,处理时每次重新获取新值时必要的。

3.  NGX_HTTP_VAR_INDEXED和NGX_HTTP_VAR_NOHASH

这两个宏主要是在SSI相关处理中用到,而ssi的处理需要用到cmcf->variables_hash,这是hash表,可以高效的找到变量。NGX_HTTP_VAR_NOHASH类型的变量压根就不会被放到这个hash表中,而从hash表中找到的变量,是ngx_http_variable_t结构,如果我们从它flags发现NGX_HTTP_VAR_INDEXED标记,那么意味着我们可以直接到r->variables中去找,至于找到后可用与否,那要另作判断了!