先看下if指令会出现的问题 原文地址:agentzh.blogspot.com/2011/03/how…
以下是翻译:
Nginx 的 if 指令在实践中确实有些奇怪。当人们对它的行为没有足够的了解时,他们可能会滥用它。在这篇文章中,我将在这里分析一些示例,以便人们可以了解并正确使用它。
简而言之,Nginx 的“if”块有效地创建了一个(嵌套的)位置块,一旦“if”条件匹配,只有内部位置块(即“if”块)的内容处理程序将被执行。
Case 1
location /proxy {
set $a 32;
if ($a = 32) {
set $a 56;
}
set $a 76;
proxy_pass http://127.0.0.1:$server_port/$a;
}
location ~ /(\d+) {
echo $1;
}
调用 /proxy 会得到 76,因为它按以下步骤工作:
-
Nginx 按照它们在配置文件中的顺序运行所有重写阶段指令,即,
set $a 32; if ($a = 32) { set $a 56; } set $a 76;
$a 的最终值为 76。
- Nginx 陷入“if”内部块,因为它的条件 $a = 32 在步骤 1 中得到满足。
- 内部块没有任何内容处理程序,ngx_proxy继承了外部范围内的内容处理程序(ngx_proxy的处理程序)(参见src/http/modules/ngx_http_proxy_module.c:2025)。
- proxy_pass 指定的配置也被内部“if”块继承(参见 src/http/modules/ngx_http_proxy_module.c:2015)
- 请求终止(并且控制流永远不会超出“if”块)。
也就是说,外部作用域中的 proxy_pass 指令将永远不会在此示例中运行。真正为您服务的是“if”内部块。
让我们看看当我们用 下面例子 覆盖内部“if”块的内容处理程序时会发生什么: Case 2
location /proxy {
set $a 32;
if ($a = 32) {
set $a 56;
echo "a = $a";
}
set $a 76;
proxy_pass http://127.0.0.1:$server_port/$a;
}
location ~ /(\d+) {
echo $1;
}
您将在访问 /proxy 时获得此信息:
a = 76
看起来违反直觉?哦,好吧,让我们看看这次发生了什么:
- Nginx 按照它们在配置文件中的顺序运行所有重写阶段指令,即,
set $a 32;
if ($a = 32) {
set $a 56;
}
set $a 76;
$a 的最终值为 76。
-
Nginx 陷入“if”内部块,因为它的条件 $a = 32 在步骤 1 中得到满足。
-
内部块确实有一个由“echo”指定的内容处理程序,然后 $a (76) 的值被发送到客户端。
-
请求终止(并且控制流永远不会超出“if”块),如案例 1。
我们确实可以选择让案例 2 按我们的意愿工作:
好的,你看到了 ngx_proxy 模块在嵌套位置之间的配置继承如何在这里发挥关键作用,并让你相信它可以按照你想要的方式工作。但是其他模块(例如我之前的一封电子邮件中提到的 echo)可能不会继承嵌套位置的内容处理程序(事实上,大多数内容处理程序模块,包括上游模块,都不会)。
在其他情况下,必须小心“if”块的配置继承的不良副作用,请考虑以下示例:
Case 4
location /proxy {
set $a 32;
if ($a = 32) {
return 404;
}
set $a 76;
proxy_pass http://127.0.0.1:$server_port/$a;
more_set_headers "X-Foo: $a";
}
location ~ /(\d+) {
echo $1;
}
在这里,ngx_header_more 的 more_set_headers 也将被“if”块创建的隐式位置继承。所以你会得到:
$ curl localhost/proxy
HTTP/1.1 404 Not Found
Server: nginx/0.8.54 (without pool)
Date: Mon, 14 Feb 2011 05:24:00 GMT
Content-Type: text/html
Content-Length: 184
Connection: keep-alive
X-Foo: 32
这可能是也可能不是你想要的:)
顺便说一句,在这种情况下 add_header 指令不会发出 X-Foo 标头,这并不意味着这里没有发生指令继承,但是 add_header 的标头过滤器将跳过 404 响应。
你看,幕后是多么的棘手!难怪人们一直吐槽...
如果你看懂上面的文章,自然下面的问题也会迎刃而解
location / {
root /usr/local/var/www/;
try_files $uri $uri/ /index.html;
if ($host ~* .*.baidu.com)
{
add_header X-Frame-Options "sameorigin"
}
}
本来想做 前端的 浏览器路由模式,访问 test.baidu.com/main 或者test.baidu.com/login 页面 都是用try_files 进入到 test.baidu.com/index.html, 并添加X-Frame-Options 头信息,但是被if 无情的截断之后出现了404