进入主题前,先来看下location的主要集中配置方式:
location / { //匹配所有的请求
root html;
index index.html index.htm;
}
location = /50x.html { //精准匹配
root html;
}
location /static/ { #前缀匹配,当请求//static/a.txt,或者为/static均不能匹配,多了/或者少了/
root static; #相对NGINX的工作目录如:/usr/local/nginx/static/,假设请求是/static/a.txt,
#则查找的文件为/usr/local/nginx/static/static/a.txt
#root /opt/static; #以/开头的认为是绝对目录,查找目录为/opt/static/static
}
location ~ ^/abcd$ { #正则匹配,大小写敏感
root abcd;
}
location ~* ^/abcd$ { #正则匹配,大小写不敏感
root abcd;
}
location ^~ ^/abcd$ { #前缀字符串前加^~可以跳过正则表达式匹配,它不需要URI完全相等,只需要匹配上前缀而且此location是当下最长匹配即可,跟前缀匹配差不多,不过前缀匹配不能跳过正则匹配。
}
location @redo { #定义一个 Location块,且该块不能被外部Client 所访问,只能被Nginx内部配置指令所访问
root redo;
}
location /tryfile {
try_files $uri @redo ;#nginx内部命令才能使用@location配置
}
location /hei/ {
alias /hello/info/;
} # 真实路径 /hello/info/index.html
location /hei/ {
root /hello/info/;
} # 真实路径 /hello/info/hei/index.html
更多匹配规则见官网location配置
一、ngx_http_core_location
location配置结构生成的部分,在博客NGINX源码之:模块配置解析(1)已做介绍,下面主要对该方法中的其他细节做解读。
除生成配置外,主要还包括URL匹配规则解析,location配置命名,location配置块内命令解析
此时不同类型的location块的配置除了完成命名,还设置对应的类型:如 = 对应的类型是exact_match;~与 ~* 对应regrex ;^~ 对应noregex;@ 对应named,另外还有noname类型,并不是在此处设置,而是在解析rewrite命令或者limit except命令时设置
location配置块内的命令解析这里就不解读了,用到的时候再看吧,只找查找对应命令的解析方法,前面篇章有介绍过如何查找。
主要可关注root、index、proxy_pass、rewrite、deny、satisfy 等
从NGINX源码之:模块配置解析(1)可知,当某个server块完成所有的location块解析后,会生成一个locations队列,location块中嵌套的location也会生成一个location队列:
ngx_http_add_location() 构建locations队列时,excat_match/regex/named/noname类型的location配置均设置到(ngx_http_location_queue_t)lq的exact成员中,剩余没有类型符开头的location配置均设置到inclusive中
二、构建location树:ngx_http_init_locations与ngx_http_init_static_location_trees
在解析完http块内所有内容后,ngx_http_block()方法中,开始进入构建location树
1、ngx_http_init_locations()
该方法中首先对locations队列进行排序:
排序完后的队列: (exact_match 或 inclusive) (排序好的,如果某个exact_match名字和inclusive location相同,exact_match排在前面) | regex(regex节点间不排序)| named(name小的在前) | noname(noname节点间不排序)
排序完成之后,完成队列裁剪,将精准匹配与前缀匹配类型继续留在locations队列中,将regex类型节点和named类型节点添加到各自对应队列,noname的直接剪除:
来看个示例:
这里有个注意点:lq = (ngx_http_location_queue_t *) q;
因为ngx_http_location_queue_t 的结构体头一个成员就是queue,因此结构体的首地址也是queue的首地址
2、 ngx_http_init_static_location_trees()
下面对其中的几个重点方法展开下:
2.1、ngx_http_join_exact_locations()
2.2、ngx_http_create_locations_list()
list创建如图:
2.3、ngx_http_create_locations_tree()
注意:node->tree的树构建时,入参prefix时当前node节点处理的prefix+当前name的长度如:当前的node是/,当前处理的prefix是0,那么当前node的tree,即当前node的list构建树时,ngx_http_create_locations_tree,传入的prefix就是1。主要为了构建node->tree的节点时,tree节点的name去掉前缀部分如:/a1,再/的node->list中,参与/的node->tree的构建,那么tree中/a1节点的name为:a1
创建的树结构如下:
三、location查找:ngx_http_core_find_location
主要来看下ngx_http_core_find_static_location():
可以看出,在static_locations满足前缀匹配查找后,r->loc_conf,是不断更改为下一个匹配的节点的loc_conf(精准或者还要继续递归tree子树),如果没有精准找到对应的节点,那么使用最后一个前缀匹配的节点的loc_conf。当匹配到前缀匹配的节点时,前缀匹配的节点分两种,一种是普通的前缀,一种是以^~开头的location前缀匹配,这种location的loc_conf会设置为noregex,这里的意思很明确,就是跳过正则匹配,从代码可以看过,匹配的前缀匹配节点,那么后面的正则匹配流程就不走了。
因此在ngx_http_core_find_location中,首先精准匹配,然后再前缀匹配,如果前缀匹配的节点不是^~ 类型但是又有正则匹配满足的话,则使用正则匹配的loc_conf。因此匹配顺序:精准 > ^~类型前缀匹配 > 正则 > 前缀匹配
关于auto_redirect的设置,主要可以参考ngx_http_proxy_pass()
这段赋值代码, 除了在proxy模块中, 同时还存在与fastcgi, grpc, memcached, scgi, uwsgi模块中。这里关系到一个重定向问题可参考auto_redirect问题这里不做讨论