zoukankan      html  css  js  c++  java
  • 聊一聊 Nginx 变量(一)

    一、什么是变量?

    变量可以认为是存放“值”的容器。而所谓“值”,在许多编程语言里,既可以是 3.14 这样的数值,也可以是 hello world 这样的字符串,甚至可以是像数组、哈希表这样的复杂数据结构。

    Nginx 的变量和 perl、php 等语言的类似,由美元符号 $ 开头,随后跟着一个字符串,代表这个变量的名称,例如 $name,可选地,这个字符串可以用花括号包围,譬如 ${name} ,合法的变量名可用字符集为 [a-zA-Z0-9_]。特别地,Nginx 支持正则子组,即 $1,$2 这样的变量。变量值只有字符串这一种类型。

    例子:

    nginx.conf 文件中有以下配置:

    server {
    	listen 8080;
    
      location /test {
      		set $foo hello;
          echo "foo: $foo";
      }
    }
    

    使用 curl 这个 HTTP 客户端在命令行上请求这个 /test 接口,可以得到:

      $ curl 'http://localhost:8080/test'
        foo: hello
    

    我们通过 set 配置指令对变量 $foo 进行了赋值操作, 把字符串 hello 赋给了它,通过“变量插值”的形式将其拼接到字符串中。

    二、变量定义

    1、主要数据结构

    1)变量跟踪结构体

    维护 Nginx 各模块支持的和配置文件中用到的变量信息结构体。

    typedef struct {
        ...
        ngx_hash_t              variables_hash;
        ngx_array_t             variables;  /* array of ngx_http_variable_t */
        ..
        ngx_hash_keys_arrays_t  *variables_keys; /* 解析时的临时存储 */
        ...
    } ngx_http_core_main_conf_t;
    

    variables_keys 只是在解析时使用的临时存储,配置解析完成后,其中的变量信息会被 ngx_http_variables_init_vars 转存到 variablesvariables_hash 中。

    不难知道变量拥有两种存放方式,第一种是储存在一个全局的 hash 表里(variables_hash);第二种则是储存在一个全局动态数组里(variables),每个变量存在一个对应的索引。

    2)变量信息结构体

    存储变量属性、变量 set_handlerget_handler 和这两个函数用到的参数值。

    struct ngx_http_variable_s {
        ngx_str_t                     name;
        ngx_http_set_variable_pt      set_handler;
        ngx_http_get_variable_pt      get_handler;
        uintptr_t                     data;
        ngx_uint_t                    flags; /* 变量属性 */
        ngx_uint_t                    index;
    };
    

    变量的属性是以下几种属性的单例或组合:

    NGX_HTTP_VAR_CHANGEABLE

    变量可被覆盖

    NGX_HTTP_VAR_NOCACHEABLE

    不可缓存,对于 noncacheable 的变量,每次取值时都需要调用其 get_handler

    NGX_HTTP_VAR_INDEXED

    保存在动态数组中

    NGX_HTTP_VAR_NOHASH

    不保存在 hash 表中

    NGX_HTTP_VAR_PREFIX

    前缀型变量,如 arg_cookie_

    示例:

    static ngx_http_variable_t  ngx_http_fastcgi_vars[] = {
    
        { ngx_string("fastcgi_script_name"), NULL,
          ngx_http_fastcgi_script_name_variable, 0,
          NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
    
        { ngx_string("fastcgi_path_info"), NULL,
          ngx_http_fastcgi_path_info_variable, 0,
          NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
    
          ngx_http_null_variable
    };
    
    3)变量值结构体
    typedef struct {
        unsigned    len:28;
    
        unsigned    valid:1;
        unsigned    no_cacheable:1;
        unsigned    not_found:1;
        unsigned    escape:1;
    
        u_char     *data;
    } ngx_variable_value_t;
    
    4)变量获取接口
    /* 获取没有索引的变量 */
    ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key)
    
    /* 根据索引获取变量,对于 nocaheable 变量会重新获取 */
    ngx_http_variable_value_t *ngx_http_get_flushed_variable(ngx_http_request_t *r, ngx_uint_t index)
    
    /* 根据索引获取变量 */
    ngx_http_variable_value_t *ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index);
    

    2、变量分类

    1)核心模块 ngx_http_core_module 提供的(内建)变量

    使用 ngx_http_core_variables 描述, 由 preconfiguration 回调函数 ngx_http_variables_add_core_vars 进行定义:

    ngx_int_t
    ngx_http_variables_add_core_vars(ngx_conf_t *cf)
    {
        ...
        ngx_http_core_main_conf_t *cmcf;
    
        cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
        cmcf->variables_keys = ngx_pcalloc(cf->temp_pool,
                                           sizeof(ngx_hash_keys_arrays_t));
        ...
        cmcf->variables_keys->pool = cf->pool;
        cmcf->variables_keys->temp_pool = cf->pool;
        ngx_hash_keys_array_init(cmcf->variables_keys, NGX_HASH_SMALL)
    
        for (v = ngx_http_core_variables; v->name.len; v++) {
            rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v,
                                  NGX_HASH_READONLY_KEY);
            ...
        }
        ...
    }
    
    2)其他功能模块中添加的变量

    ngx_http_fastcgi_module 提供的变量使用 ngx_http_fastcgi_vars 描述,由 preconfiguration 回调函数 ngx_http_fastcgi_add_variables 进行定义:

    static ngx_int_t
    ngx_http_fastcgi_add_variables(ngx_conf_t *cf)
    {
        ngx_http_variable_t *var, *v;
    
        for (v = ngx_http_fastcgi_vars; v->name.len; v++) {
            var = ngx_http_add_variable(cf, &v->name, v->flags);
            ...
            var->get_handler = v->get_handler;
            var->data = v->data;
        }
    
        return NGX_OK;
    }
    
    3)使用 set 创建的变量

    ngx_http_rewrite_module 提供的 set 指令定义的自定义变量由其配置解析函数 ngx_http_rewrite_set 进行定义:

    static char *
    ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
    {
        ...
        value = cf->args->elts;
        ...
        value[1].len--;
        value[1].data++;
    
        v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGEABLE);
        ...
        index = ngx_http_get_variable_index(cf, &value[1]);
        ...
    }
    

    上述三种类型变量信息都被直接 (ngx_hash_add_key) 或间接 (ngx_http_add_variable) 存储到了 variables_keys 中。

  • 相关阅读:
    [Trie][并查集]JZOJ 5822 量子纠缠
    [模拟]JZOJ 5820 非法输入
    SAM模板
    [树形DP]JZOJ 5819 大逃杀
    [MST][dij]JZOJ 5818 做运动
    [暴力]JZOJ 5817 抄代码
    [概率期望][树形DP][LCA]JZOJ 5814 树
    认证组件
    注册接口
    视图家族 & 路由组件
  • 原文地址:https://www.cnblogs.com/fu3638/p/14059295.html
Copyright © 2011-2022 走看看