有些童鞋的误区
1、 location 的匹配顺序是“先匹配正则,再匹配普通”。 矫正: location 的匹配顺序其实是“先匹配普通,再匹配正则”。我这么说,大家一定会反驳我,因为按“先匹配普通,再匹配正则”解释不了大家平时习惯的按“先匹配正则,再匹配普通”的实践经验。这里我只能暂时解释下,造成这种误解的原因是:正则匹配会覆盖普通匹配(实际的规则,比这复杂,后面会详细解释)。 2、 location 的执行逻辑跟 location 的编辑顺序无关。 矫正:这句话不全对,“普通 location ”的匹配规则是“最大前缀”,因此“普通 location ”的确与 location 编辑顺序无关;但是“正则 location ”的匹配规则是“顺序匹配,且只要匹配到第一个就停止后面的匹配”;“普通 location ”与“正则 location ”之间的匹配顺序是?先匹配普通 location ,再“考虑”匹配正则 location 。注意这里的“考虑”是“可能”的意思,也就是说匹配完“普通 location ”后,有的时候需要继续匹配“正则 location ”,有的时候则不需要继续匹配“正则 location ”。两种情况下,不需要继续匹配正则 location :( 1 )当普通 location 前面指定了“ ^~ ”,特别告诉 Nginx 本条普通 location 一旦匹配上,则不需要继续正则匹配;( 2 )当普通 location 恰好严格匹配上,不是最大前缀匹配,则不再继续匹配正则。 总结一句话: “正则 location 匹配让步普通 location 的严格精确匹配结果;但覆盖普通 location 的最大前缀匹配结果”官方文档解释
REFER: http://wiki.nginx.org/NginxHttpCoreModule#location location syntax: location [=|~|~*|^~|@] /uri/ { ... } default: no context: server This directive allows different configurations depending on the URI. (译者注:1 、different configurations depending on the URI 说的就是语法格式:location [=|~|~*|^~|@] /uri/ { ... } ,依据不同的前缀“= ”,“^~ ”,“~ ”,“~* ”和不带任何前缀的(因为[A] 表示可选,可以不要的),表达不同的含义, 简单的说尽管location 的/uri/ 配置一样,但前缀不一样,表达的是不同的指令含义。2 、查询字符串不在URI 范围内。例如:/films.htm?fid=123 的URI 是/films.htm 。) It can be configured using both literal strings and regular expressions. To use regular expressions, you must use a prefix:- "~" for case sensitive matching
- "~*" for case insensitive matching
- Directives with the "=" prefix that match the query exactly. If found, searching stops.
- All remaining directives with conventional strings. If this match used the "^~" prefix, searching stops.
- Regular expressions, in the order they are defined in the configuration file.
- If #3 yielded a match, that result is used. Otherwise, the match from #2 is used.
- / -> configuration A
- /documents/document.html -> configuration B
- /images/1.gif -> configuration C
- /documents/1.jpg -> configuration D
安装Nginx
wget http://nginx.org/download/nginx-1.1.0.tar.gz tar zxvf nginx-1.1.0.tar.gz ./configure make make install 需要注意的是在 configure 这步遇到点小麻烦: ./configure: error: the HTTP rewrite module requires the PCRE library. 安装 nginx 的时候, rewrite 模块默认是需要被安装的。但是 rewrite 模块所依赖的 PCRE 库需要额外安装。 You can either disable the module by using --without-http_rewrite_module option, or install the PCRE library into the system, or build the PCRE library statically from the source with nginx by using --with-pcre=<path> option. 解决办法: http://apps.hi.baidu.com/share/detail/34331473 先执行: yum -y install pcre-devel openssl openssl-devel 把依赖的东西安装上。 备注: PCRE (Perl Compatible Regular Expressions )是perl语言正则表达式。 Nginx的rewrite的正则表达式采用的是Perl语法集(常识:正则表达式有不同的语法集,我们常见的grep指令如果需要采用Perl语法集,需要grep -P 来指定)。 location 实例练习 Nginx 的语法形式是: location [=|~|~*|^~|@] /uri/ { ... } ,意思是可以以“ = ”或“ ~* ”或“ ~ ”或“ ^~ ”或“ @ ”符号为前缀,当然也可以没有前缀(因为 [A] 是表示可选的 A ; A|B 表示 A 和 B 选一个),紧接着是 /uri/ ,再接着是 {…} 指令块,整个意思是对于满足这样条件的 /uri/ 适用指令块 {…} 的指令。 上述各种 location 可分两大类,分别是:“普通 location ”,官方英文说法是 location using literal strings 和“正则 location ”,英文说法是 location using regular expressions 。其中“普通 location ”是以“ = ”或“ ^~ ”为前缀或者没有任何前缀的 /uri/ ;“正则 location ”是以“ ~ ”或“ ~* ”为前缀的 /uri/ 。 那么,当我们在一个 server 上下文编写了多个 location 的时候, Nginx 对于一个 HTTP 请求,是如何匹配到一个 location 做处理呢?用一句话简单概括 Nginx 的 location 匹配规则是:“正则 location ”让步 “普通 location ”的严格精确匹配结果;但覆盖 “普通 location ”的最大前缀匹配结果。理解这句话,我想通过下面的实例来说明。#1 先普通 location ,再正则 location
周边不少童鞋告诉我, nginx 是“先匹配正则 location 再匹配普通 location ”,其实这是一个误区, nginx 其实是“先匹配普通 location ,再匹配正则 location ”,但是普通 location 的匹配结果又分两种:一种是“严格精确匹配”,官方英文说法是“ exact match ”;另一种是“最大前缀匹配”,官方英文说法是“ Literal strings match the beginning portion of the query - the most specific match will be used. ”。我们做个实验: 例题 1 :假设 nginx 的配置如下 server { listen 9090; server_name localhost; location / { root html; index index.html index.htm; deny all; } location ~ \.html$ { allow all; } } 附录 nginx 的目录结构是: nginx->html->index.html 上述配置的意思是: location / {… deny all;} 普通 location 以“ / ”开始的 URI 请求(注意任何 HTTP 请求都必然以“ / ”开始,所以“ / ”的意思是所有的请求都能被匹配上),都拒绝访问; location ~\.html$ {allow all;} 正则 location 以 .html 结尾的 URI 请求,都允许访问。 测试结果: [root@web108 ~]# curl http://localhost:9090/ <html> <head><title>403 Forbidden</title></head> <body bgcolor="white"> <center><h1>403 Forbidden</h1></center> <hr><center>nginx/1.1.0</center> </body> </html> [root@web108 ~]# curl http://localhost:9090/index.html <html> <head> <title>Welcome to nginx!</title> </head> <body bgcolor="white" text="black"> <center><h1>Welcome to nginx!</h1></center> </body> </html> [root@web108 ~]# curl http://localhost:9090/index_notfound.html <html> <head><title>404 Not Found</title></head> <body bgcolor="white"> <center><h1>404 Not Found</h1></center> <hr><center>nginx/1.1.0</center> </body> </html> [root@web108 ~]# 测试结果如下:URI 请求 | HTTP 响应 |
curl http://localhost:9090/ | 403 Forbidden |
curl http://localhost:9090/index.html | Welcome to nginx! |
curl http://localhost:9090/index_notfound.html | 404 Not Found |
#2 普通 location 的“隐式”严格匹配
例题 2 :我们在例题 1 的基础上增加精确配置 server { listen 9090; server_name localhost; location /exact/match.html { allow all; } location / { root html; index index.html index.htm; deny all; } location ~ \.html$ { allow all; } } 测试请求: [root@web108 ~]# curl http://localhost:9090/exact/match.html <html> <head><title>404 Not Found</title></head> <body bgcolor="white"> <center><h1>404 Not Found</h1></center> <hr><center>nginx/1.1.0</center> </body> </html> [root@web108 ~]# 结果进一步验证了“普通 location ”的“严格精确”匹配会终止对正则 location 的搜索。这里我们小结下“普通 location ”与“正则 location ”的匹配规则:先匹配普通 location ,再匹配正则 location ,但是如果普通 location 的匹配结果恰好是“严格精确( exact match )”的,则 nginx 不再尝试后面的正则 location ;如果普通 location 的匹配结果是“最大前缀”,则正则 location 的匹配覆盖普通 location 的匹配。也就是前面说的“正则 location 让步普通 location 的严格精确匹配结果,但覆盖普通 location 的最大前缀匹配结果”。#3 普通 location 的“显式”严格匹配和“ ^~ ” 前缀
上面我们演示的普通 location 都是不加任何前缀的,其实普通 location 也可以加前缀:“ ^~ ”和“ = ”。其中“ ^~ ”的意思是“非正则,不需要继续正则匹配”,也就是通常我们的普通 location ,还会继续搜索正则 location (恰好严格精确匹配除外),但是 nginx 很人性化允许配置人员告诉 nginx 某条普通 location ,无论最大前缀匹配,还是严格精确匹配都终止继续搜索正则 location ;而“ = ”则表达的是普通 location 不允许“最大前缀”匹配结果,必须严格等于,严格精确匹配。 例题 3 :“ ^~ ”前缀的使用 server { listen 9090; server_name localhost; location /exact/match.html { allow all; } location ^~ / { root html; index index.html index.htm; deny all; } location ~ \.html$ { allow all; } } 把例题 2 中的 location / {} 修改成 location ^~ / {} ,再看看测试结果:URI 请求 | 修改前 | 修改后 |
curl http://localhost:9090/ | 403 Forbidden | 403 Forbidden |
curl http://localhost:9090/index.html | Welcome to nginx! | 403 Forbidden |
curl http://localhost:9090/index_notfound.html | 404 Not Found | 403 Forbidden |
curl http://localhost:9090/exact/match.html | 404 Not Found | 404 Not Found |
URI 请求 | 修改前 | 修改后 |
curl http://localhost:9090/ | 403 Forbidden | 403 Forbidden |
curl http://localhost:9090/index.html | Welcome to nginx! | Welcome to nginx! |
curl http://localhost:9090/index_notfound.html | 404 Not Found | 404 Not Found |
curl http://localhost:9090/exact/match.html | 404 Not Found | 404 Not Found |
curl http://localhost:9090/test.jsp | 403 Forbidden | 404 Not Found |
#4 正则 location 与编辑顺序
location 的指令与编辑顺序无关,这句话不全对。对于普通 location 指令,匹配规则是:最大前缀匹配(与顺序无关),如果恰好是严格精确匹配结果或者加有前缀“ ^~ ”或“ = ”(符号“ = ”只能严格匹配,不能前缀匹配),则停止搜索正则 location ;但对于正则 location 的匹配规则是:按编辑顺序逐个匹配(与顺序有关),只要匹配上,就立即停止后面的搜索。 配置 3.1 server { listen 9090; server_name localhost; location ~ \.html$ { allow all; } location ~ ^/prefix/.*\.html$ { deny all; } } 配置 3.2 server { listen 9090; server_name localhost; location ~ ^/prefix/.*\.html$ { deny all; } location ~ \.html$ { allow all; } } 测试结果:URI 请求 | 配置 3.1 | 配置 3.2 |
curl http://localhost:9090/regextest.html | 404 Not Found | 404 Not Found |
curl http://localhost:9090/prefix/regextest.html | 404 Not Found | 403 Forbidden |
URI 请求 | 配置 3.1 | 配置 3.2 |
curl http://localhost:9090/prefix/t.html | 403 Forbidden | 403 Forbidden |
curl http://localhost:9090/prefix/mid/t.html | 404 Not Found | 404 Not Found |