Nginx关于location的匹配规则详解.docx
Nginx关于location的匹配规则详解http://iyunv.com/eyesmore/
有些童鞋的误区
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 differentconfigurations depending on the URI.
(译者注:1、different configurations depending on theURI 说的就是语法格式:location [=|~|~*|^~|@] /uri/ { ... } ,依据不同的前缀“=”,“^~”,“~”,“~*”和不带任何前缀的(因为表示可选,可以不要的),表达不同的含义,简单的说尽管location的/uri/配置一样,但前缀不一样,表达的是不同的指令含义。2、查询字符串不在URI范围内。例如:/films.htm?fid=123的URI是/films.htm。)
It can be configured using bothliteral strings and regular expressions. To use regular expressions, you mustuse a prefix:
[*]"~" for case sensitive matching
[*]"~*" for case insensitive matching
译文:上文讲到location /uri/可通过使用不同的前缀,表达不同的含义。对这些不同前缀,分下类,就2大类:正则location,英文说法是locationusing regular expressions和普通location,英文说法是location using literal strings。那么其中“~”和“~*”前缀表示正则location,“~”区分大小写,“~*”不区分大小写;其他前缀(包括:“=”,“^~”和“@”)和无任何前缀的都属于普通location。
To determinewhich locationdirective matches a particular query, the literal stringsare checked first.
译文:对于一个特定的HTTP请求(aparticular query),nginx应该匹配哪个location块的指令呢(注意:我们在nginx.conf配置文件里面一般会定义多个location的)?匹配规则是:先匹配普通location(再匹配正则表达式)。注意:官方文档这句话就明确说了,先普通location,而不是有些同学的误区“先匹配正则location”。
Literal stringsmatch the beginning portion of the query - the most specific match will beused.
前面说了“普通location”与“正则location”之间的匹配规则是:先匹配普通location,再匹配正则location。那么,“普通location”内部(普通location与普通location)是如何匹配的呢?简单的说:最大前缀匹配。原文:1、match the beginning portion of the query(说的是匹配URI的前缀部分beginning portion); 2、the most specific match will be used(因为location不是“严格匹配”,而是“前缀匹配”,就会产生一个HTTP请求,可以“前缀匹配”到多个普通location,例如:location /prefix/mid/ {}和location /prefix/ {},对于HTTP请求 /prefix/mid/t.html,前缀匹配的话两个location都满足,选哪个?原则是:the most specific match,于是选的是location/prefix/mid/ {})。
Afterwards,regular expressions are checked in the order defined in the configuration file.The first regular expression to match thequery will stop the search.
这段话说了两层意思,第一层是:“Afterwards, regular expressions are checked”,意思是普通location先匹配,而且选择了最大前缀匹配后,不能就停止后面的匹配,最大前缀匹配只是一个临时的结果,nginx还需要继续检查正则location(但至于最终才能普通location的最大前缀匹配,还是正则location的匹配,截止当前的内容还没讲,但后面会讲)。第二层是“regular expressions are checked in the order defined in the configurationfile. The first regular expression to match the query will stop the search.”,意思是说“正则location”与“正则location”内部的匹配规则是:按照正则location在配置文件中的物理顺序(编辑顺序)匹配的(这句话就说明location并不是一定跟顺序无关,只是普通location与顺序无关,正则location还是与顺序有关的),并且只要匹配到一条正则location,就不再考虑后面的(这与“普通location”与“正则location”之间的规则不一样,“普通location”与“正则location”之间的规则是:选择出“普通location”的最大前缀匹配结果后,还需要继续搜索正则location)。
If no regularexpression matches are found, the result from the literal string search isused.
这句话回答了“普通location”的最大前缀匹配结果与继续搜索的“正则location”匹配结果的决策关系。如果继续搜索的“正则location”也有匹配上的,那么“正则location”覆盖“普通location”的最大前缀匹配(因为有这个覆盖关系,所以造成有些同学以为正则location先于普通location执行的错误理解);但是如果“正则location”没有能匹配上,那么就用“普通location”的最大前缀匹配结果。
For case insensitive operating systems, like Mac OS X or Windows withCygwin, literal string matching is done in a case insensitive way (0.7.7).However, comparison is limited to single-byte locale's only.
Regular expression may contain captures (0.7.40), which can then be usedin other directives.
It is possibleto disable regular expression checks after literal string matching by using"^~" prefix. Ifthe most specific match literal location has this prefix: regular expressionsaren't checked.
通常的规则是,匹配完了“普通location”指令,还需要继续匹配“正则location”,但是你也可以告诉Nginx:匹配到了“普通location”后,不再需要继续匹配“正则location”了,要做到这一点只要在“普通location”前面加上“^~”符号(^表示“非”,~表示“正则”,字符意思是:不要继续匹配正则)。
By using the "=" prefix wedefine the exactmatch between request URI and location. When matchedsearch stops immediately. E.g., if therequest "/" occurs frequently, using "location = /" willspeed up processing of this request a bit as search will stop after firstcomparison.
除了上文的“^~”可以阻止继续搜索正则location外,你还可以加“=”。那么如果“^~”和“=”都能阻止继续搜索正则location的话,那它们之间有什么区别呢?区别很简单,共同点是它们都能阻止继续搜索正则location,不同点是“^~”依然遵守“最大前缀”匹配规则,然而“=”不是“最大前缀”,而是必须是严格匹配(exact match)。
这里顺便讲下“location / {}”和“location = / {}”的区别,“location / {}”遵守普通location的最大前缀匹配,由于任何 URI都必然以“/”根开头,所以对于一个URI,如果有更specific的匹配,那自然是选这个更specific的,如果没有,“/”一定能为这个URI垫背(至少能匹配到“/”),也就是说“location / {}”有点默认配置的味道,其他更specific的配置能覆盖overwrite这个默认配置(这也是为什么我们总能看到location / {}这个配置的一个很重要的原因)。而“location = / {}”遵守的是“严格精确匹配exact match”,也就是只能匹配http://host:port/ 请求,同时会禁止继续搜索正则location。因此如果我们只想对“GET /”请求配置作用指令,那么我们可以选“location = / {}”这样能减少正则location的搜索,因此效率比“location / {}”高(注:前提是我们的目的仅仅只想对“GET /”起作用)。
On exact matchwith literal location without "=" or "^~" prefixes search is also immediatelyterminated.
前面我们说了,普通location匹配完后,还会继续匹配正则location;但是nginx允许你阻止这种行为,方法很简单,只需要在普通location前加“^~”或“=”。但其实还有一种“隐含”的方式来阻止正则location的搜索,这种隐含的方式就是:当“最大前缀”匹配恰好就是一个“严格精确(exactmatch)”匹配,照样会停止后面的搜索。原文字面意思是:只要遇到“精确匹配exact match”,即使普通location没有带“=”或“^~”前缀,也一样会终止后面的匹配。
先举例解释下,后面例题会用实践告诉大家。假设当前配置是:location /exact/match/test.html {配置指令块1},location /prefix/ {配置指令块2} 和 location ~ \.html$ {配置指令块3},如果我们请求 GET /prefix/index.html,则会被匹配到指令块3,因为普通location /prefix/依据最大匹配原则能匹配当前请求,但是会被后面的正则location覆盖;当请求GET /exact/match/test.html,会匹配到指令块1,因为这个是普通location的exact match,会禁止继续搜索正则location。
To summarize,the order in which directives are checked is as follows:
[*]Directiveswith the "=" prefix that match the query exactly. If found,searching stops.
[*]Allremaining directives with conventional strings. If this match used the"^~" prefix, searching stops.
[*]Regularexpressions, in the order they are defined in the configuration file.
[*]If #3yielded a match, that result is used. Otherwise, the match from #2 isused.
这个顺序没必要再过多解释了。但我想用自己的话概括下上面的意思“正则location匹配让步普通location的严格精确匹配结果;但覆盖普通location的最大前缀匹配结果”。
It is important to know that nginx does the comparison against decodedURIs. For example, if you wish to match"/images/%20/test", then you must use "/images/ /test" todetermine the location.
在浏览器上显示的URL一般都会进行URLEncode,例如“空格”会被编码为%20,但是Nginx的URL的匹配都是针对URLDecode之后的。也就是说,如果你要匹配“/images/%20/test”,你写location的时候匹配目标应该是:“/images/ /test”。
Example:
location = / {
# matches thequery / only.
[ configuration A]
}
location / {
# matches any query, since all queries begin with /, but regular
# expressions andany longer conventional blocks will be
# matched first.
[ configuration B]
}
location ^~ /images/ {
# matches any query beginning with /images/and halts searching,
# so regularexpressions will not be checked.
[ configuration C]
}
location ~*\.(gif|jpg|jpeg)$ {
# matches anyrequest ending in gif, jpg, or jpeg. However, all
# requests to the/images/ directory will be handled by
# ConfigurationC.
[ configuration D]
}
上述这4个location的配置,没什么好解释的,唯一需要说明的是location / {},原文的注释严格来说是错误的,但我相信原文作者是了解规则的,只是文字描述上简化了下,但这个简化容易给读者造成“误解:先检查正则location,再检查普通location”。原文:“matches any query, since all queries begin with /, but regular expressionsand any longer conventional blocks will be matched first.”大意是说:“location /{} 能够匹配所有HTTP请求,因为任何HTTP请求都必然是以‘/’开始的(这半句没有错误)。但是,正则location和其他任何比‘/’更长的普通location(location/ {}是普通location里面最短的,因此其他任何普通location都会比它更长,当然location = / {} 和 location ^~ / {}是一样长的)会优先匹配(matched first)。”原文作者说“butregular expressions will be matched first.”应该只是想说正则location会覆盖这里的location/ {},但依然是普通location / {}先于正则location匹配,接着再正则location匹配;但其他更长的普通location(any longer conventional blocks)的确会先于location / {}匹配。
Example requests:
[*]/ ->configuration A
[*]/documents/document.html-> configuration B
[*]/images/1.gif-> configuration C
[*]/documents/1.jpg-> configuration D
Note that youcould define these 4 configurations in any order and the results would remainthe same.
需要提醒下:这里说“in any order”和“… remain the same”是因为上面只有一个正则location。文章前面已经说了正则location的匹配是跟编辑顺序有关系的。
While nestedlocations are allowed by the configuration file parser, their use isdiscouraged and may produce unexpected results.
实际上nginx的配置文件解析程序是允许location嵌套定义的(location/ { location /uri/ {} })。但是我们平时却很少看见这样的配置,那是因为nginx官方并不建议大家这么做,因为这样会导致很多意想不到的后果。
The prefix"@" specifies a named location. Such locations are not used duringnormal processing of requests, they are intended only to process internallyredirected requests (see error_page, try_files).
文章开始说了location的语法中,可以有“=”,“^~”,“~”和“~*”前缀,或者干脆没有任何前缀,还有“@”前缀,但是后面的分析我们始终没有谈到“@”前缀。文章最后点内容,介绍了“@”的用途:“@”是用来定义“Named Location”的(你可以理解为独立于“普通location(location using literal strings)”和“正则location(location using regular expressions)”之外的第三种类型),这种“Named Location”不是用来处理普通的HTTP请求的,它是专门用来处理“内部重定向(internally redirected)”请求的。注意:这里说的“内部重定向(internallyredirected)”或许说成“forward”会好点,以为内internally redirected是不需要跟浏览器交互的,纯粹是服务端的一个转发行为。
安装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 intothe system, or build the PCRE library
statically from the source with nginx byusing --with-pcre=<path> option.
解决办法:http://apps.hi.baidu.com/share/detail/34331473
先执行:yum -y install pcre-developenssl openssl-devel 把依赖的东西安装上。
备注: PCRE(Perl Compatible Regular Expressions)是perl语言正则表达式。 Nginx的rewrite的正则表达式采用的是Perl语法集(常识:正则表达式有不同的语法集,我们常见的grep指令如果需要采用Perl语法集,需要grep -P 来指定)。
location实例练习
Nginx的语法形式是:location[=|~|~*|^~|@] /uri/ { ... } ,意思是可以以“=”或“~*”或“~”或“^~”或“@”符号为前缀,当然也可以没有前缀(因为是表示可选的A;A|B表示A和B选一个),紧接着是/uri/,再接着是{…}指令块,整个意思是对于满足这样条件的/uri/适用指令块{…}的指令。
上述各种location可分两大类,分别是:“普通location”,官方英文说法是locationusing literal strings 和“正则location”,英文说法是locationusing 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 mostspecific 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请求,都允许访问。
测试结果:
# curlhttp://localhost:9090/
<html>
<head><title>403Forbidden</title></head>
<body bgcolor="white">
<center><h1>403Forbidden</h1></center>
<hr><center>nginx/1.1.0</center>
</body>
</html>
# curlhttp://localhost:9090/index.html
<html>
<head>
<title>Welcome tonginx!</title>
</head>
<body bgcolor="white" text="black">
<center><h1>Welcome tonginx!</h1></center>
</body>
</html>
# curlhttp://localhost:9090/index_notfound.html
<html>
<head><title>404 NotFound</title></head>
<body bgcolor="white">
<center><h1>404 NotFound</h1></center>
<hr><center>nginx/1.1.0</center>
</body>
</html>
#
测试结果如下:
URI请求
HTTP响应
curl http://localhost:9090/
403 Forbidden
curl http://localhost:9090/index.html
Welcome to nginx!
curlhttp://localhost:9090/index_notfound.html
404 Not Found
curl http://localhost:9090/的结果是“403 Forbidden”,说明被匹配到“location / {..deny all;}”了,原因很简单HTTP请求GET / 被“严格精确”匹配到了普通location/ {},则会停止搜索正则location;
curl http://localhost:9090/index.html结果是“Welcometo nginx!”,说明没有被“location / {…deny all;}”匹配,否则会403 Forbidden,但/index.html的确也是以“/”开头的,只不过此时的普通location/ 的匹配结果是“最大前缀”匹配,所以Nginx会继续搜索正则location,location ~ \.html$ 表达了以.html结尾的都allow all; 于是接着就访问到了实际存在的index.html页面。
curl http://localhost:9090/index_notfound.html 同样的道理先匹配location / {},但属于“普通location的最大前缀匹配”,于是后面被“正则location” location ~ \.html$ {} 覆盖了,最终allow all;但的确目录下不存在index_notfound.html页面,于是404 NotFound。
如果此时我们访问http://localhost:9090/index.txt会是什么结果呢?显然是deny all;因为先匹配上了 location / {..deny all;} 尽管属于“普通location”的最大前缀匹配结果,继续搜索正则location,但是 /index.txt 不是以.html结尾的,正则location失败,最终采纳普通location的最大前缀匹配结果,于是deny all了。
# curlhttp://localhost:9090/index.txt
<html>
<head><title>403Forbidden</title></head>
<body bgcolor="white">
<center><h1>403Forbidden</h1></center>
<hr><center>nginx/1.1.0</center>
</body>
</html>
#
#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;
}
}
测试请求:
# curlhttp://localhost:9090/exact/match.html
<html>
<head><title>404 NotFound</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.1.0</center>
</body>
</html>
#
结果进一步验证了“普通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
curlhttp://localhost:9090/index_notfound.html
404 Not Found
403 Forbidden
curl http://localhost:9090/exact/match.html
404 Not Found
404 Not Found
除了GET /exact/match.html是404 Not Found,其余都是403 Forbidden,原因很简单所有请求都是以“/”开头,所以所有请求都能匹配上“/”普通location,但普通location的匹配原则是“最大前缀”,所以只有/exact/match.html 匹配到location /exact/match.html {allow all;},其余都location^~ / {deny all;} 并终止正则搜索。
例题4:“=”前缀的使用
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;
}
}
例题4相对例题2把location / {} 修改成了 location = / {} ,再次测试结果:
URI请求
修改前
修改后
curl http://localhost:9090/
403 Forbidden
403 Forbidden
curl http://localhost:9090/index.html
Welcome to nginx!
Welcome to nginx!
curlhttp://localhost:9090/index_notfound.html
404 Not Found
404 Not Found
curlhttp://localhost:9090/exact/match.html
404 Not Found
404 Not Found
curlhttp://localhost:9090/test.jsp
403Forbidden
404Not Found
最能说明问题的测试是GET /test.jsp,实际上/test.jsp没有匹配正则location(location ~\.html$),也没有匹配location = / {} ,如果按照location / {}的话,会“最大前缀”匹配到普通location / {},结果是deny all。
#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
curlhttp://localhost:9090/prefix/regextest.html
404 Not Found
403 Forbidden
解释:
Location ~ ^/prefix/.*\.html$ {deny all;} 表示正则location对于以/prefix/开头,.html结尾的所有URI请求,都拒绝访问; location ~\.html${allow all;} 表示正则location对于以.html结尾的URI请求,都允许访问。实际上,prefix的是~\.html$的子集。
在“配置3.1”下,两个请求都匹配上 location ~\.html$ {allow all;},并且停止后面的搜索,于是都允许访问,404Not Found;在“配置3.2”下,/regextest.html无法匹配prefix,于是继续搜索~\.html$,允许访问,于是404 Not Found;然而/prefix/regextest.html 匹配到prefix,于是deny all,403Forbidden。
配置3.3
server {
listen 9090;
server_name localhost;
location /prefix/ {
deny all;
}
location /prefix/mid/ {
allow all;
}
}
配置3.4
server {
listen 9090;
server_name localhost;
location /prefix/mid/ {
allow all;
}
location /prefix/ {
deny all;
}
}
测试结果:
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
测试结果表明:普通location的匹配规则是“最大前缀”匹配,而且与编辑顺序无关。
#5 “@”前缀Named Location使用
REFER: http://wiki.nginx.org/HttpCoreModule#error_page
假设配置如下:
server {
listen 9090;
server_name localhost;
location / {
root html;
index index.html index.htm;
allow all;
}
#error_page 404 http://www.baidu.com #直接这样是不允许的
error_page 404 = @fallback;
location @fallback {
proxy_pass http://www.baidu.com;
}
}
上述配置文件的意思是:如果请求的URI存在,则本nginx返回对应的页面;如果不存在,则把请求代理到baidu.com上去做个弥补(注:nginx当发现URI对应的页面不存在,HTTP_StatusCode会是404,此时error_page 404指令能捕获它)。
测试一:
# curlhttp://localhost:9090/nofound.html -i
HTTP/1.1 302 Found
Server: nginx/1.1.0
Date: Sat, 06 Aug 2011 08:17:21 GMT
Content-Type: text/html; charset=iso-8859-1
Location:http://localhost:9090/search/error.html
Connection: keep-alive
Cache-Control: max-age=86400
Expires: Sun, 07 Aug 2011 08:17:21 GMT
Content-Length: 222
<!DOCTYPE HTML PUBLIC "-//IETF//DTDHTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="http://www.baidu.com/search/error.html">here</a>.</p>
</body></html>
#
当我们GET /nofound.html发送给本nginx,nginx找不到对应的页面,于是error_page 404 = @fallback,请求被代理到http://www.baidu.com,于是nginx给http://www.baidu.com发送了GET /nofound.html,但/nofound.html页面在百度也不存在,百度302跳转到错误页。
直接访问http://www.baidu.com/nofound.html结果:
# curl http://www.baidu.com/nofound.html -i
HTTP/1.1 302 Found
Date: Sat, 06 Aug 2011 08:20:05 GMT
Server: Apache
Location: http://www.baidu.com/search/error.html
Cache-Control: max-age=86400
Expires: Sun, 07 Aug 2011 08:20:05 GMT
Content-Length: 222
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTDHTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <ahref="http://www.baidu.com/search/error.html">here</a>.</p>
</body></html>
#
测试二:访问一个nginx不存在,但baidu存在的页面
# curl http://www.baidu.com/duty/ -i
HTTP/1.1 200 OK
Date: Sat, 06 Aug 2011 08:21:56 GMT
Server: Apache
P3P: CP=" OTI DSP COR IVA OUR IND COM"
P3P: CP=" OTI DSP COR IVA OUR IND COM"
Set-Cookie:BAIDUID=5C5D2B2FD083737A0C88CA7075A6601A:FG=1; expires=Sun, 05-Aug-12 08:21:56GMT; max-age=31536000; path=/; domain=.baidu.com; version=1
Set-Cookie:BAIDUID=5C5D2B2FD083737A2337F78F909CCB90:FG=1; expires=Sun, 05-Aug-12 08:21:56GMT; max-age=31536000; path=/; domain=.baidu.com; version=1
Last-Modified: Wed, 05 Jan 2011 06:44:53GMT
ETag: "d66-49913b8efe340"
Accept-Ranges: bytes
Content-Length: 3430
Cache-Control: max-age=86400
Expires: Sun, 07 Aug 2011 08:21:56 GMT
Vary: Accept-Encoding,User-Agent
Connection: Keep-Alive
Content-Type: text/html
<!DOCTYPE HTML PUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
。。。。
</body>
</html>
显示,的确百度这个页面是存在的。
#curlhttp://localhost:9090/duty/ -i
HTTP/1.1 200 OK
Server: nginx/1.1.0
Date: Sat, 06 Aug 2011 08:23:23 GMT
Content-Type: text/html
Connection: keep-alive
P3P: CP=" OTI DSP COR IVA OUR IND COM"
P3P: CP=" OTI DSP COR IVA OUR IND COM"
Set-Cookie:BAIDUID=8FEF0A3A2C31D277DCB4CC5F80B7F457:FG=1; expires=Sun, 05-Aug-12 08:23:23GMT; max-age=31536000; path=/; domain=.baidu.com; version=1
Set-Cookie:BAIDUID=8FEF0A3A2C31D277B1F87691AFFD7440:FG=1; expires=Sun, 05-Aug-12 08:23:23GMT; max-age=31536000; path=/; domain=.baidu.com; version=1
Last-Modified: Wed, 05 Jan 2011 06:44:53GMT
ETag: "d66-49913b8efe340"
Accept-Ranges: bytes
Content-Length: 3430
Cache-Control: max-age=86400
Expires: Sun, 07 Aug 2011 08:23:23 GMT
Vary: Accept-Encoding,User-Agent
<!DOCTYPE HTML PUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
。。。
</body>
</html>
当curl http://localhost:9090/duty/ -i时,nginx没找到对应的页面,于是error_page = @fallback,把请求代理到baidu.com。注意这里的error_page = @fallback不是靠重定向实现的,而是所说的“internally redirected(forward)”。
页:
[1]