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 ^~ /urilocation /uri同时存在,那么nginx会提示你有重复的location配置


rootalias指令的区别

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

那么最终找到的就是/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之后,请求被重定向到百度去了。

注意:

  1. try_files后面至少要跟两个参数,最后一个参数是内部重定向。
  2. 最后重定向的时候,并不会保留$args,如果需要这些,要自己明确保留。如try_files $uri $uri/ /index.php?q=$uri&$args;
  3. 文件一定要在前面加上/
  4. 如果最后一个参数是文件的话,那么相当于请求静态文件。

再举个例子:

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里面的/

有时候在浏览器里面输入网址,会自动在末尾给你加上一个/,有时候却不会。

这里面的主要区别就是,在末尾给你加上一个/,这是明确表示要请求的是一个目录。

而结尾不加/则相当于请求一个文件。

参考:

  1. Nginx的location配置详解

  2. nginx配置location总结及rewrite规则写法

  3. nginx的try_files指令使用说明