欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

nginx处理http(http变量篇)

发布时间:2024/2/28 编程问答 54 豆豆
生活随笔 收集整理的这篇文章主要介绍了 nginx处理http(http变量篇) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

nginx http变量定义

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;  //变量索引值 }


正则变量

typedef struct {ngx_uint_t                    capture; ngx_int_t                     index; } ngx_http_regex_variable_t


 

typedef struct {ngx_regex_t                  *regex;        //正则表达式ngx_uint_t                    ncaptures;    //俘获的正则变量数量ngx_http_regex_variable_t    *variables;    //正则变量表ngx_uint_t                    nvariables;   //正则变量数量ngx_str_t                     name;         //正则变量名 } ngx_http_regex_t

 

typedef struct {ngx_http_regex_t             *regex;      //正则表达式void                         *value;      //正则值 } ngx_http_map_regex_t


正则字典

typedef struct {ngx_hash_combined_t           hash;      //hash表 #if (NGX_PCRE)ngx_http_map_regex_t         *regex;     //正则表ngx_uint_t                    nregex;    //元素数量 #endif } ngx_http_map_t


变量值定义

typedef struct {unsigned    len:28;          //变量的长度unsigned    valid:1;         //valid 表示变量是否有效的标记unsigned    no_cacheable:1;  //表示变量可否缓存unsigned    not_found:1;     //表示没找到变量的值unsigned    escape:1;        //变量中是否有空格u_char     *data;            //变量数据 } ngx_variable_value_t


nginx变量类型

NGX_HTTP_VAR_CHANGEABLE     //可变变量 NGX_HTTP_VAR_NOCACHEABLE    //不可变变量 NGX_HTTP_VAR_INDEXED         NGX_HTTP_VAR_NOHASH NGX_HTTP_VAR_PREFIX


nginx http变量原理及使用 
1.添加http变量(普通变量)

ngx_http_variable_t * ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags) { ...if (name->len == 0) {/*变量名为空,认定无效同时返回错误*/ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"invalid variable name \"$\"");return NULL;}if (flags & NGX_HTTP_VAR_PREFIX) {/*flags为前缀标记 加入到前缀变量中*/return ngx_http_add_prefix_variable(cf, name, flags);}/*获取main作用域的配置*/cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);/*main作用域配置的变量表*/key = cmcf->variables_keys->keys.elts;for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) {if (name->len != key[i].key.len|| ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0){  /*不在main作用域的变量表中*/continue;}/*获取变量的key值*/v = key[i].value;if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) {/*变量带有changeable标记 判定变量出现了重复 随即返回空值*/ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"the duplicate \"%V\" variable", name);return NULL;}/*清除掉flags中的weak标记*/v->flags &= flags | ~NGX_HTTP_VAR_WEAK;return v;}/*分配变量内存*/v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t));if (v == NULL) {/*可用内存不足 返回空值*/return NULL;}/*拷贝变量名*/v->name.len = name->len;v->name.data = ngx_pnalloc(cf->pool, name->len);if (v->name.data == NULL) {return NULL;}//变量名小写处理ngx_strlow(v->name.data, name->data, name->len);/*变量成员初始化*/v->set_handler = NULL;v->get_handler = NULL;v->data = 0;v->flags = flags;v->index = 0;/*将变量添加到 variable_keys集合中*/rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0);if (rc == NGX_ERROR) {/*添加失败 返回空值*/return NULL;}if (rc == NGX_BUSY) {/*变量名与variables_keys集合中的变量出现了重复*/ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"conflicting variable name \"%V\"", name);return NULL;}/*返回新增的变量*/return v; }


2.添加prefix[前缀]变量

static ngx_http_variable_t * ngx_http_add_prefix_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags) { ...//得到前缀变量表v = cmcf->prefix_variables.elts;for (i = 0; i < cmcf->prefix_variables.nelts; i++) {if (name->len != v[i].name.len|| ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0){   /*没找到 跳过*/continue;}v = &v[i];if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) {/*同普通变量处理*/ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"the duplicate \"%V\" variable", name);return NULL;}v->flags &= flags | ~NGX_HTTP_VAR_WEAK;return v;}/*添加到prefix_variables变量表中*/v = ngx_array_push(&cmcf->prefix_variables);if (v == NULL) {return NULL;}v->name.len = name->len;v->name.data = ngx_pnalloc(cf->pool, name->len);if (v->name.data == NULL) {return NULL;}ngx_strlow(v->name.data, name->data, name->len);/*变量初始化*/v->set_handler = NULL;v->get_handler = NULL;v->data = 0;v->flags = flags;v->index = 0;return v; }



3.通过变量名获取变量的index索引值

ngx_int_t ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name) {if (name->len == 0) {/*传入的变量名是空的 返回错误*/ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"invalid variable name \"$\"");return NGX_ERROR;}/*得到main作用域的变量表*/v = cmcf->variables.elts;if (v == NULL) {/*发现变量表为空 则创建一个变量表 默认有4个元素*/if (ngx_array_init(&cmcf->variables, cf->pool, 4,sizeof(ngx_http_variable_t))!= NGX_OK){return NGX_ERROR;}} else {/*变量表存在 则在变量表中进行查找*/for (i = 0; i < cmcf->variables.nelts; i++) {if (name->len != v[i].name.len|| ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0){  /*变量名不匹配 跳过*/continue;}//找到了变量return i;}}/*发现变量表中没有这个变量 则将变量加入到变量表中*/v = ngx_array_push(&cmcf->variables);if (v == NULL) {//添加失败 则返回错误return NGX_ERROR;}/*拷贝变量名称到变量表中*/v->name.len = name->len;v->name.data = ngx_pnalloc(cf->pool, name->len);if (v->name.data == NULL) {return NGX_ERROR;}ngx_strlow(v->name.data, name->data, name->len);//初始化变量v->set_handler = NULL;v->get_handler = NULL;v->data = 0;v->flags = 0;v->index = cmcf->variables.nelts - 1;//返回变量的索引值(即在变量数组中的序号)return v->index; }



3.通过变量的索引值获取变量值

ngx_http_variable_value_t * ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index) {if (cmcf->variables.nelts <= index) {/*使用的索引值超过了数组的范围 返回空值*/ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,"unknown variable index: %ui", index);return NULL;}if (r->variables[index].not_found || r->variables[index].valid) {/*变量not_found或者valid为真 直接返回变量值*/return &r->variables[index];}/*获取配置的变量数组*/v = cmcf->variables.elts;if (ngx_http_variable_depth == 0) {/*如果变量的深度为0 表明变量的值正在进行刷新 返回空值*/ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,"cycle while evaluating variable \"%V\"",&v[index].name);return NULL;}/*减少一次变量深度*/ngx_http_variable_depth--;if (v[index].get_handler(r, &r->variables[index], v[index].data)== NGX_OK){  /*获取变量ok 增加一次变量深度*/ngx_http_variable_depth++;if (v[index].flags & NGX_HTTP_VAR_NOCACHEABLE) {/*变量本身是nocacheable标记 则重新加上 (以防在get函数中被修改)*/r->variables[index].no_cacheable = 1;}/*返回变量*/return &r->variables[index];} /*获取变量出错 *///增加一次变量深度ngx_http_variable_depth++;/* valid设置为假 not_found设置为真 valid表明变量无效 not_found表示没找到变量的值 在下次调用中能复用还未刷新的变量值*/r->variables[index].valid = 0;r->variables[index].not_found = 1;return NULL; }



4.获取刷新的变量值

ngx_http_variable_value_t * ngx_http_get_flushed_variable(ngx_http_request_t *r, ngx_uint_t index) {/*通过index索引找到变量值*/v = &r->variables[index];if (v->valid || v->not_found) {/*变量值是valid有效的或者是not_found标记 */if (!v->no_cacheable) {/*如果变量值可以缓存 返回变量值*/return v;}/*重置 valid和not_found标记 以通过get函数获取变量 即刷新变量的作用*/v->valid = 0;v->not_found = 0;}/*通过3中的函数来取得变量的值*/return ngx_http_get_indexed_variable(r, index); }


5.通过变量名及key值取得变量值

ngx_http_variable_value_t * ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key) { ... /*在配置的变量表中取得变量 这儿使用hash值和名字来取得变量的*/v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);if (v) {/*找到了变量 */if (v->flags & NGX_HTTP_VAR_INDEXED) {return ngx_http_get_flushed_variable(r, v->index);}/*发现变量的深度为0 注意变量深度是全局静态变量 针对所有请求而言意味着变量正在进行“刷新” 此时返回空值*/if (ngx_http_variable_depth == 0) {ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,"cycle while evaluating variable \"%V\"", name);return NULL;}/*减少变量深度*/ngx_http_variable_depth--;/*为变量值分配空间*/vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));/*通过变量绑定的get函数计算得到变量的值*/if (vv && v->get_handler(r, vv, v->data) == NGX_OK) {//成功获得变量  增加一次变量深度ngx_http_variable_depth++;return vv;}//出错 增加一次变量深度并且返回空值ngx_http_variable_depth++;return NULL;}/*为变量值分配空间*/vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));if (vv == NULL) {/*分配出错 返回空值*/return NULL;}len = 0;/*在variables_hash中没有找到变量 则从prefix_variables变量表中查找*/v = cmcf->prefix_variables.elts;n = cmcf->prefix_variables.nelts;for (i = 0; i < cmcf->prefix_variables.nelts; i++) {if (name->len >= v[i].name.len && name->len > len&& ngx_strncmp(name->data, v[i].name.data, v[i].name.len) == 0){  /*查找到变量 取得变量名的长度和索引值*/len = v[i].name.len;n = i;}}/*索引值在prefix_variables变量表的范围之内 则通过绑定的get函数取得变量值*/if (n != cmcf->prefix_variables.nelts) {if (v[n].get_handler(r, vv, (uintptr_t) name) == NGX_OK) {return vv;}/*获取变量出错 返回空值*/return NULL;}/*没有找到变量 not_found为真 返回变量值*/vv->not_found = 1;return vv; }



6.获取http请求的变量

static ngx_int_t ngx_http_variable_request(ngx_http_request_t *r, ngx_http_variable_value_t *v,uintptr_t data) {ngx_str_t  *s;/*通过成员在ngx_http_request_t结构中的偏移计算得到成员的地址*/s = (ngx_str_t *) ((char *) r + data);  if (s->data) { /*成员有数据 得到数据*/v->len = s->len;v->valid = 1;v->no_cacheable = 0;v->not_found = 0;v->data = s->data;} else {//成员中没有数据 进行not_found标记v->not_found = 1;}return NGX_OK; }


7.获取http_request_t成员中的“大小”类型的变量

static ngx_int_t ngx_http_variable_request_get_size(ngx_http_request_t *r,ngx_http_variable_value_t *v, uintptr_t data) {size_t  *sp;/*通过结构体的偏移得到 地址*/sp = (size_t *) ((char *) r + data);/*为变量值分配空间*/v->data = ngx_pnalloc(r->pool, NGX_SIZE_T_LEN);if (v->data == NULL) {//分配失败 返回错误return NGX_ERROR;}/*拷贝数据到 变量值中*/v->len = ngx_sprintf(v->data, "%uz", *sp) - v->data;v->valid = 1;v->no_cacheable = 0;v->not_found = 0;return NGX_OK; }



8.通过变量值设置http_request_t中的长度成员值

static void ngx_http_variable_request_set_size(ngx_http_request_t *r,ngx_http_variable_value_t *v, uintptr_t data) { ...//得到变量的长度及数据信息    val.len = v->len;val.data = v->data;/*解析字符串得到“长度”大小*/s = ngx_parse_size(&val);if (s == NGX_ERROR) {/*解析失败 报错*/ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,"invalid size \"%V\"", &val);return;}/*取得位于结构体中的地址*/sp = (ssize_t *) ((char *) r + data);/* *引用取得值 并进行设置 内存地址无变化*/*sp = s;return; }



9.获得http头变量的值

static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v,uintptr_t data) {ngx_table_elt_t  *h;/*通过结构体中的成员的偏移得到 hash表的元素*/h = *(ngx_table_elt_t **) ((char *) r + data); if (h) {/*存在 则取得元素的值 并设置到变量中*/v->len = h->value.len;v->valid = 1;v->no_cacheable = 0;v->not_found = 0;v->data = h->value.data;} else {/*不存在 进行not_found标记*/v->not_found = 1;}return NGX_OK; }



10.添加ngx_http_core_module中的变量

ngx_int_t ngx_http_variables_add_core_vars(ngx_conf_t *cf) { ...cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);/*为ngx_http_core_module的变量分配空间*/cmcf->variables_keys = ngx_pcalloc(cf->temp_pool,sizeof(ngx_hash_keys_arrays_t));if (cmcf->variables_keys == NULL) {/*分配失败 返回错误*/return NGX_ERROR;}/*内存池设置*/cmcf->variables_keys->pool = cf->pool;cmcf->variables_keys->temp_pool = cf->pool;/*初始化variables_keys hash表*/if (ngx_hash_keys_array_init(cmcf->variables_keys, NGX_HASH_SMALL)!= NGX_OK){return NGX_ERROR;}/*初始化prefix_variables数组*/if (ngx_array_init(&cmcf->prefix_variables, cf->pool, 8,sizeof(ngx_http_variable_t))!= NGX_OK){return NGX_ERROR;}/*添加http core变量 注意cv取得的是指针数组*/for (cv = ngx_http_core_variables; cv->name.len; cv++) {v = ngx_http_add_variable(cf, &cv->name, cv->flags);if (v == NULL) {/*变量添加失败 返回错误*/return NGX_ERROR;}/*设置变量值*/*v = *cv;}return NGX_OK; }



初始化配置的变量

ngx_int_t ngx_http_variables_init_vars(ngx_conf_t *cf) { ...cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);/*取得core_module的变量数组*/v = cmcf->variables.elts;/*取得prefix_variables变量数组*/pv = cmcf->prefix_variables.elts;/*取得variables_keys数组*/key = cmcf->variables_keys->keys.elts;for (i = 0; i < cmcf->variables.nelts; i++) {for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {av = key[n].value;if (v[i].name.len == key[n].key.len&& ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len)/*在variables hash表中找到了变量*/== 0){/*设置变量的get函数 及回调参数*/v[i].get_handler = av->get_handler;v[i].data = av->data;/*将变量标记为 INDEXED*/av->flags |= NGX_HTTP_VAR_INDEXED;/*设置变量的flags标记*/v[i].flags = av->flags;//设置变量的索引值av->index = i;/*变量没有设置get函数或者变量为weak标记(即不通过get进行获取)跳出循环*/if (av->get_handler == NULL|| (av->flags & NGX_HTTP_VAR_WEAK)){break;}goto next;}}/*在variables_keys hash表中没有找到变量在prefix_variables表中查找变量*/len = 0;av = NULL;for (n = 0; n < cmcf->prefix_variables.nelts; n++) {if (v[i].name.len >= pv[n].name.len && v[i].name.len > len&& ngx_strncmp(v[i].name.data, pv[n].name.data, pv[n].name.len)== 0){   /*找到了变量 取得变量和变量名的长度*/av = &pv[n];len = pv[n].name.len;}}if (av) {/*变量存在 设置变量的get函数及回调参数以及flags*/v[i].get_handler = av->get_handler;v[i].data = (uintptr_t) &v[i].name;v[i].flags = av->flags;/*完成*/goto next;}if (v[i].get_handler == NULL) {/*发现没有get函数 报错并且返回错误*/ngx_log_error(NGX_LOG_EMERG, cf->log, 0,"unknown \"%V\" variable", &v[i].name);return NGX_ERROR;}next:continue;}for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {av = key[n].value;if (av->flags & NGX_HTTP_VAR_NOHASH) {/*对于不使用hash进行索引查找的变量 将key值置为空值*/key[n].key.data = NULL;}}/*hash表进行初始化*/hash.hash = &cmcf->variables_hash;hash.key = ngx_hash_key;hash.max_size = cmcf->variables_hash_max_size;hash.bucket_size = cmcf->variables_hash_bucket_size;hash.name = "variables_hash";hash.pool = cf->pool;hash.temp_pool = NULL;/*将vaiables_keys数据拷贝到 hash表中*/if (ngx_hash_init(&hash, cmcf->variables_keys->keys.elts,cmcf->variables_keys->keys.nelts)!= NGX_OK){return NGX_ERROR;}/*将variables_keys hash表赋值为空 并且返回*/cmcf->variables_keys = NULL;return NGX_OK; }


--------------------- 
作者:huzilinitachi 
来源:CSDN 
原文:https://blog.csdn.net/huzilinitachi/article/details/79902950 
版权声明:本文为博主原创文章,转载请附上博文链接!

超强干货来袭 云风专访:近40年码龄,通宵达旦的技术人生

总结

以上是生活随笔为你收集整理的nginx处理http(http变量篇)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。