本文主要是介绍Nginx基础. Nginx通配散列表,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
之前学习过Nginx中的普通散列表, 关于其初始化以及整体的构造有了大致的了解.接下来就是在普通散列表的基础上, 分析更复杂的散列表构造. 因为Nginx作为一个Web服务器, 它的各种散列表中的关键字多以字符串为主, 特别是URI域名, 比如 www.ben.com.
既然是这样, 那么Nginx就需要去支持带有通配符的主机域名, 即带"*"的域名, 包括前置通配符, 如 *.test.com; 或是后置通配符, 如www.ben.*. 注意的是, 不支持通配符在中间.
支持通配符的散列表
文章开头提到Nginx支持具有前置通配符或是后置通配符或是没有通配符的域名.
所谓支持通配符的散列表, 就是把基本散列表中元素的关键字, 用去除通配符以后的字符作为关键字加入. 例如, 对于关键字 "www.ben.*", 这样带通配符的情况, 直接建立一个专用的后置通配符散列表, 存储元素的关键字为"www.ben". 这样, 如果要检索 www.ben.com 是否匹配 www.ben.* , 可以用Nginx提供的方法 ngx_hash_find_wc_tail检索, 此函数会把要查询的 www.ben.com 转化为 www.ben 字符串再开始查询.
同理, 对于关键字为 "*.ben.com"的元素, 也直接建立一个前置通配符的散列表, 存储元素的关键字为 "com.ben." , 如果要检索“smtp.ben.com”是否匹配 ".ben.com", 直接使用Nginx提供的 ngx_hash_find_wc_head方法查询. 该方法会把要查询的 "smtp.ben.com"转化为 "com.ben."再开始查询
散列表的结构体定义如下:
typedef struct {ngx_hash_t hash;void *value;
} ngx_hash_wildcard_t;
当使用此支持通配符的散列表作为某容器的元素时, 可以使用这个指针指向用户数据. (这个字段是用来存放某个已经达到末尾的通配符url对应的value值,如果通配符url没有达到末尾,这个字段为NULL.)
可以看到这个结构体只是简单的对基本散列表容器的封装.
下面说明一下Nginx对于server_name主机名通配符的支持规则:
首先选择完全匹配的主机名. 比如"www.ben.com"就先在基本散列表中寻找"www.ben.com"是否存在
如果没有找到, 然后选择通配符在前面的主机名. "*.ben.com"
最后, 还没找到的话, 比如 "www.ben.*"
想要在一个搜索中对3个散列表进行寻找, Nginx提供了一个结构体:
typedef struct {ngx_hash_t hash;ngx_hash_wildcard_t *wc_head;ngx_hash_wildcard_t *wc_tail;
} ngx_hash_combined_t;
这个结构体中就包含了三个散列表, 基本散列表, 通配符在头部的散列表, 通配符在最后的散列表.
这里再次提一下, 前置通配符散列表中元素的关键字, 在把*通配符去掉后, 会按照 "." 符号分隔, 并以倒序的方式作为关键字来存储元素.
在进行查询时, 待查询的关键字name也会以同样的方式被转化, 之后再做递归查询.
进行前置通配符或是后置通配符的查询时, 可以用上面提到的函数进行查询. 在对ngx_hash_combined_t结构体进行查找时, 使用ngx_hash_find_combined进行查找. 查找规则符合上面的顺序
也就是: ngx_hash_find ---> ngx_hash_find_wc_head ---> ngx_hash_find_wc_tail
初始化函数.
既然要使用到支持通配符的散列表, 那么先看其初始化函数.
传入的ngx_hash_key_t中关键字已经被处理过(注释会讲到)
ngx_int_t
ngx_hash_wildcard_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,ngx_uint_t nelts)
{size_t len, dot_len;ngx_uint_t i, n, dot;ngx_array_t curr_names, next_names;ngx_hash_key_t *name, *next_name;ngx_hash_init_t h;ngx_hash_wildcard_t *wdc;//初始化两个动态数组. 接下来会使用. 其中元素都是 ngx_hash_key_t类型的//curr_names就是会被最终传到ngx_hash_init的数组if (ngx_array_init(&curr_names, hinit->temp_pool, nelts,sizeof(ngx_hash_key_t))!= NGX_OK)...//next_names最终被传到ngx_hash_wildcard_init中去的数组if (ngx_array_init(&next_names, hinit->temp_pool, nelts,sizeof(ngx_hash_key_t))!= NGX_OK)...//从整体看, 一个大循环. 目的是构造一个ngx_hash_key_t类型的数组, 传递给ngx_hash_init函数去构造一个哈希表.//从细节看, 这其中会递归调用ngx_hash_wildcard_init函数. 从而最终生成n级哈希表.//值得注意的是, 这个循环的使用的变量 n 不是递增的. 而是会随i而变化的. i也是一个循环的变量, 下面会看到for (n = 0; n < nelts; n = i) {dot = 0;//寻找第一个 ".", 这样目的是两个: 1. 看是否存在 "," 2. 找到构建这个散列表的所需关键字长度for (len = 0; len < names[n].key.len; len++) {if (names[n].key.data[len] == '.') {dot = 1;break;}
这篇关于Nginx基础. Nginx通配散列表的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!