nginx location匹配规则
首先说几种常见的匹配规则
精确匹配=
location = /uri {
……
}
对开头匹配^~
location ^~ /uri {
……
}
正则表达式区分大小写~
location ~ pattern {
……
}
正则表达式不区分大小写~*
location ~* pattern {
……
}
无修饰符
location /uri {
……
}
通用匹配
location / {
……
}
location的匹配并不是绝对按照声明顺序来的,它有一定的优先级,优先级从高往低如下:
=
全匹配^~
匹配开头~
或者~*
正则表达式匹配前缀(2017-12-1修订:不是匹配前缀,而是匹配是否是uri的子串)- 无修饰符,匹配字符串比较长
- 无修饰符,匹配字符串比较短
关于~
和无修饰符的优先级,这里有一个比较容易混淆的地方:
举例:
location ~ /tt/ {
规则A;
}
location /tt/qq/ {
规则B;
}
假如说此时来了一个uri是/tt/qq/
,那么规则A
会被匹配到。表示~
的优先级是高于字符串全匹配的
又假如来了一个uri是/ww/tt/qq
,那么还是规则A
会被匹配到。因为~
并不是匹配开头,它是匹配任意子串,而^~
才是匹配开头。
关于同样是~
,相互比较的优先级是这样的:
匹配子串长 > 匹配子串短
举例来说:
location ~ /aa/ {
规则C;
}
location ~ /aa/bb/ {
规则D;
}
假如说uri是/mm/aa/bb/
,那么规则D
会被匹配到,因为location ~ /aa/bb/
匹配了更长的子串。
假如说uri是/mm/aa/
,那么规则C
会被匹配到,因为/aa/bb/
并不是/mm/aa/
的子串。
还有一点,如果
location ^~ /uri
和location /uri
同时存在,那么nginx会提示你有重复的location配置
root
与alias
指令的区别
location /img/ {
alias /var/www/image/;
}
以上情况,如果uri里面是/img/head.jpg
,那么就是去找/var/www/image/head.jpg
这个文件。
location /img/ {
root /var/www/image;
}
以上情况,如果uri里面是/img/head.jpg
,那么就是去找/var/www/image/img/head.jpg
这个文件。
还有一个重要的区别是alias后面必须要用“/”结束,否则会找不到文件,而root后面则可以不用“/”结束。
index
指令
index
指令只用来处理以"/"结尾的请求,它的使用形式可以是这样的:
index index.php index.html myindex.html /home/users/nemo/index.html;
它依次按照顺序查找文件,其中最后一个文件可以是一个绝对路径的文件。它的作用相当于在内部做重定向。
location = / {
index index.html;
}
location / {
...
}
比如说在这个例子里面,先进入第一个=
location,根据index的指令去查找index.html,然后内部重定向,以/index.html
匹配进入了第二个location。
如果你觉得上面的 location = /
和 location /
容易误解,那么可以换成自定义的uri,如下:
location /tsindex/ {
root /home/users/nemo/forfun;
index index.html;
}
location /tsindex/index.html {
root /home/users/nemo/dir2;
}
假设uri是http://xxx.xxx.com/tsindex/
,
如果目录结构是这样的:
- nemo
- forfun
- index.html
- tsindex
- index.html
- dir2
- index.html
- tsindex
- index.html
- forfun
那么最终找到的就是/home/users/nemo/dir2/tsindex/index.html
**注意:**内部转发是不会在access_log里面体现的
try_files
指令
try_files
指令的用处是:逐个查找文件,返回第一个找到的文件或者文件夹,当所有都找不到的时候,执行最一个参数进行内部重定向。
try_files指令
语法:try_files file ... uri 或 try_files file ... = code
默认值:无
作用域:server location
举例子:
server {
listen 80;
server_name yousite.com;
location / {
root /home/users/nemo;
try_files /test.html /index.html @nemo;
}
location @nemo {
rewrite ^/(.*)$ http://www.baidu.com;
}
}
在这里,先是进入location /
规则,触发了里面的try_files
命令,希望找到/home/nemo/test.html
文件,但是没找到。然后又去找/home/nemo/index.html
文件。如果找到了,就直接返回这个文件,没找到就执行最后的@nemo
。
这个@nemo
是自定义的一个规则变量,进入location @nemo
之后,请求被重定向到百度去了。
注意:
try_files
后面至少要跟两个参数,最后一个参数是内部重定向。- 最后重定向的时候,并不会保留
$args
,如果需要这些,要自己明确保留。如try_files $uri $uri/ /index.php?q=$uri&$args;
- 文件一定要在前面加上
/
。 - 如果最后一个参数是文件的话,那么相当于请求静态文件。
再举个例子:
server {
listen 80;
server_name yousite.com;
location / {
root /home/users/nemo;
try_files /test.html /end.html;
}
location ~ \.html$ {
root /home/users/nemo;
}
}
上方的配置文件里面,如果请求的是http://yoursite.com/
,那么会进入location /
里面,去查找/home/users/nemo/test.html
文件。
如果没找到,就内部重定向到http://yoursite.com/end.html
,再次去寻找可以匹配的location规则,进入location ~ \.html$
,返回/home/users/nemo/end.html
,如果不存在,就是404。
如果上面只有location /
,没有location ~ \.html$
,那么就会进入location /
死循环。
再来说一下参数是文件夹的情况:
server {
listen 80;
server_name yousite.com;
location / {
root /home/users/nemo;
try_files /dir/ /end.html;
}
location ~ \.html$ {
root /home/user/nemo;
}
location /dir/ {
root /home/users/nemo;
index index.php;
}
}
看上面这个配置,如果请求的是http://yoursite.com/
,那么会进入location /
里面,去查找/home/users/nemo/dir/
文件夹,找不到就重定向到http://yoursite.com/end.html
。
如果找到了/home/users/nemo/dir/
文件夹,那么此时地址栏里的请求变成了http://yoursite.com/dir/
,就会重新进入location进行规则匹配。如果此时的location配置仍然只有location /
和location ~ \.html$
两项,那么势必又会进入location /
,从而造成死循环。所以,新定义了一个location /dir/
规则。
location /dir/ {
root /home/users/nemo;
index index.php;
}
上面这个规则查找的是/home/users/nemo/dir/index.php
文件。
location /dir/ {
root /home/users/nemo;
try_files /index.php 404;
}
上面这个规则查找的是/home/users/nemo/index.php
文件。
以上算是说了一下try_files的用法,常用的配置是try_files $uri $uri/ /index.php?q=$uri&$args
。我比较喜欢在try_files里面使用自定义的@
。
下面来说一下url里面的/
有时候在浏览器里面输入网址,会自动在末尾给你加上一个/
,有时候却不会。
这里面的主要区别就是,在末尾给你加上一个/
,这是明确表示要请求的是一个目录。
而结尾不加/
则相当于请求一个文件。
参考: