前言
Nginx的location就相当于url路由,Nginx根据location的配置来决定究竟如何处理一个请求。
Nginx通过将一个请求的url与location进行对比,来决定将该请求扔到哪个location对应的处理策略中。
一、location的匹配规则
文档:Module ngx_http_core_module
上面是文档,我将location的简单的总结为以下几点:
概念:
Nginx的location分为两类:一类是prefix string;另一类是regular expression。
**location**?[?`=`|`~`|`~*`|`^~`]`_uri_`{ ... }
**location**?`@``_name_`{ ... }
什么是prefix string
不以 ~* ,~,@开头的location。
默认大小写敏感。
例如:
location = / {
[ configuration A ]
}#上面是精准匹配(exact URI),这种匹配会匹配完整的URI。也就是只有当URI为/的时候,才会命中。
location / {
[ configuration B ]
}location /documents/ {
[ configuration C ]
}location ^~ /images/ {
[ configuration D ]
}
这些都是prefix string location。
精准匹配:=开头,后面跟上路径,这种location必须URI与location完全相等,然后才能匹配命中。
排除正则匹配:以^~开头,后面跟上路径,这种location一旦匹配命中,Nginx便不再进行正则匹配。
普通的匹配:直接以路径开头。
这三种location都是prefix string location,对于prefix string location 的匹配来说,Nginx选取与request的URI相似程度最高的prefix string location作为longest match prefix string。
以上面的location为例:
/test/test2将命中location /。
/将命中location = /。
/documents/test1/test2和/documents/将命中 location /documents/。
/images/test1/test2将命中location ^~ /images/。
什么是regular expression?
即以~* ,~开头的location,它们表示这是一个正则表达式。
其中*表示大小写不敏感,表示大小写敏感。
例如:
location ~* .(gif|jpg|jpeg)$ {
[ configuration E ]
} #大小写不敏感location ~ .(Gif|jPg|jpeg)$ {
[ configuration E ]
} #大小写敏感
正则表达式匹配中,大小写敏感的优先级更高,所以Nginx总是先测试大小写敏感的正则。
Nginx采用的PCRE正则表达式。
PCRE是Perl的兼容正则表达式(实际上并不是完全兼容,会有所区别。)。
文档:
A Regular Expression Tester for NGINX and NGINX Plus - NGINX
perlretut - Perl regular expressions tutorial - Perldoc Browser
perlre - Perl regular expressions - Perldoc Browser
特殊的location
以@开头的location,叫做named location,它不参与location的匹配,但是它可以直接被其他directive调用。
主要作用就是在别的指令中,直接将一个request传递给该location处理。
因此,我在开头并没有将它算作一类location,在我眼里,它只是一个类似于PL的语法糖的东西。
典型应用:
1、错误处理
error_page 404 = @fallback;
location @fallback {
proxy_pass http://www.linuxhub.org;
}2、如果URI不存在,则把请求代理到www.linuxhub.org上去做个弥补
location / {
try_files $uri @linuxhub;
}
location @linuxhub {
proxy_pass http://www.linuxhub.org;
}
匹配规则:
对于prefix string location 的匹配来说,Nginx选取与request的URI相似程度最高的prefix string location作为longest match prefix string。
总的来说,匹配过程分为两个阶段:第一阶段是Prefix String匹配;第二阶段是正则匹配。
对于第一阶段来说,
首先比较精准匹配,如果精准匹配命中,直接结束匹配过程,该精准匹配作为此次location匹配的结果;如果精准匹配没命中,则比较其他Prefix String Location。
比较其它的Prefix String Location,其遵循如下:
依次比较location,选取与URI相似度最高的,匹配路径最长的location作为longest match prefix location;如果该longest match prefix location是一个排除正则表达式(即^~开头)的location,那么就会结束匹配过程,该location命中。
如果该longest match prefix location不是一个排除正则表达式(即^~开头)的location,那么就进入正则匹配阶段。
对于第二阶段来说,
正则匹配阶段很简单,那就是按照配置文件,自上而下一次匹配,如果命中,则结束匹配过程,命中的location作为。否则,如果直到结束都没有命中,那么此时就选用第一阶段的longest match prefix location作为此次location匹配的结果。
二、location匹配中的一些坑
浏览器中的输入:
www.test.com
那么实际上的URI会是http://www.test.com/,没错,会自动在后面添加一个/。顶级域名后面会自动添加顶级路径。
浏览器中输入:
www.test.com/test1
那么实际上的URI会是http://www.test.com/test1。域名后面如果已经添加了顶级域名,则后面不会自动添加一个/。
如果 URI 结构是https://domain.com/的形式,尾部有没有 / 都不会造成重定向。因为浏览器在发起请求的时候,默认加上了 / 。虽然很多浏览器在地址栏里也不会显示 / 。这一点,可以访问百度验证一下。
重点坑:
如果 URI 的结构是https://domain.com/some-dir/。尾部如果缺少 / 将导致重定向。因为根据约定,URL 尾部的 / 表示目录,没有 / 表示文件。所以访问 /some-dir/ 时,服务器会自动去该目录下找对应的默认文件。如果访问 /some-dir 的话,服务器会先去/目录下找 some-dir 文件,找不到的话会将 some-dir 当成目录,重定向到 /some-dir/ ,去该目录下找默认文件。
三、如何编写location
按照上面的匹配规则,可以按照如下配置location:
1、最前面写精准匹配规则
精准匹配规则一般配置给高频URI,提高匹配效率。例如首页,登录页等。
2、接着写排除正则的匹配规则
排除正则匹配可以配置给一般路径资源,这样可以提高匹配效率,因为一旦命中,3就不会执行了。
一般来说,有什么需要添加的URI匹配,都优先添加到这一块。
3、接着写正则匹配
正则匹配一般配置给一些特殊路径的资源。
可以有多条正则,越精确的正则应该越放到前面,因为正则一旦命中,直接下面的正则就不匹配了。
4、默认的根路径匹配
这个和1以及2都是属于prefix string location匹配,一旦1,2,3都不命中,那么最后就会匹配到这里了。
如下:
location = / {
#规则A #一般首页会非常频繁,所以设置精准匹配,提高匹配效率。
}
location = /login {
#规则B #一般登录页也会非常频繁,所以设置精准匹配,提高匹配效率。
}
location ^~ /static/ {
#规则C #一般来说,静态资源是访问最多的URI,所以放在这里。
}
#对于有某些特殊路径或后缀的资源,写在正则匹配中。
location ~ .(gif|jpg|png|js|css)$ {
#规则D
}
location ~* .png$ {
#规则E
}
#默认的根路径匹配,上面的都不命中的URI,全部都走这里。
location / {
#规则H
}
按照上面这样编写,思路清晰,便于维护。
路径的匹配优先级一目了然,URI的路径匹配自上而下,只要命中获得结果,就终止匹配流程,匹配效率也极高。