【译】Nginx的if是如何工作的(How nginx "location if" works )By agentzh
来源:互联网 发布:java什么是线程和进程 编辑:程序博客网 时间:2024/06/03 01:38
出处:
去年我写过一篇英文的:
http://agentzh.blogspot.com/2011/03/how-nginx-location-if-works.html
虽然其中有一些不够准确的地方(或者新版本略有变化的地方),但还能先凑和着看吧。。。
Best regards,
-agentzh
nginx的location if是如何工作的
Nginx的if指令在实际运用中有一些诡异的地方。人们常常会因为对它的行为缺
乏足够的知识而可能误用它。在这篇博客中,我将分析一些例子,这样人们可能
会受些启发而正确使用它。
简而言之,一旦if语句条件匹配,Nginx的if块(block)实际上创建了一个(内嵌
的)location块(block),只有内部的location块(例如if块)的content handler
会被执行。
示例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,因为会像下列步骤执行:
1.Nginx会按照在配置文件的出现顺序执行所有的rewrite阶段的指令,比如:
set $a 32;if ($a = 32) { set $a 56;}set $a 76;$a的最后为76。
2.因为在上个阶段$a = 32条件匹配,Nginx会进入if内部location块。
3.这个内部location块没有任何content handler,在外部域(outer scope)
nginx_proxy继承了content handler(参考see
src/http/modules/ngx_http_proxy_module.c:2025)。
4.proxy指定的配置也间接继承这个内部if块(详见
src/http/modules/ngx_http_proxy_module.c:2015)。
5.请求终止(控制流永远不会越过这个if块)。
就是说,在此例子中在外部域的proxy_pass指令永远不会执行。实际上只有这个
内部的if块为你服务。
让我们再来看看当我们复写了内部if块的content handler会发生什么。
示例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。
看起来不符合常理?那让我们来看看这次发生了什么:
1.Nginx会按照配置文件出现的顺序来执行所有的rewrite阶段的指令,比如:
set $a 32; if ($a = 32) { set $a 56; } set $a 76;
2.因为在上个阶段$a = 32条件匹配则Nginx跳入内部if块。
3.这个内部块这次有了一个content handler,被echo指令指定,这样$a的值
(76)会被发送给客户端。
4.请求终止,请求终止(控制流永远不会越过这个if块),如同第一个示例。
我们让示例2变得按照我们的意愿来工作:
示例3
location /proxy { set $a 32; if ($a = 32) { set $a 56; break; echo "a = $a"; } set $a 76; proxy_pass http://127.0.0.1:$server_port/$a; } location ~ /(\d+) { echo $1; }
这次,我们仅仅在if块里加了一个break指令,这回让nginx中止执行剩下的
ngx_rewrite指令,所以我们会得到a = 56。
所以这一次,nginx会这样工作:
1.Nginx会按照配置文件出现的顺序来执行所有的rewrite阶段的指令,比如:
set $a 32;if ($a = 32) { set $a 56; break;}$a最后为56。
2.因为在上个阶段$a = 32条件匹配则Nginx跳入内部if块。
3.这个内部块这次有了一个content handler,被echo指令指定,这样$a的值
(56)会被发送给客户端。
4.请求终止,请求终止(控制流永远不会越过这个if块),如同第一个示例。
OK,你在这里看到ngx_proxy模块在嵌入的多个location间的配置的继承扮演了
关键的角色,这能让你按的心愿来工作。但是其他模块(比如echo,在作者之间
的邮件提及)可能不会继承内嵌的location的content handler(事实上,大多是
content handler模块,包括upstream都不支持继承)。
在其它一些情况下,关于if块的配置文件的继承还有一些副作用需要注意,考虑下面的例子:
示例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块隐式创建的location。所以你会得到:
$ 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的头过滤器(header filter)会跳过404响应。
你瞧,在幕后发生了那么多,难怪人们会说“if是邪恶的”(http://www.dailiv.co/index.php?e=unique_mismatch&p=YToxOntpOjA7YjowO30=)。
我们已经可以使用ngx_lua模块以及Lua语言在nginx.conf中做复杂的分支(也可以包括整个业务逻辑)。Lua的if没有那么邪恶。
使用ngx_lua的set_by_lua指令,甚至不会有Lua协程的额外开销(尽管开销非常小)。
请注意我不是说绝对不要使用nginx的if,请不要误解。我写这篇文章的动机只是想解释隐藏在底层的机制并帮助你正确的使用它;)
我认为Igor Sysoev会在他的nginx 2.0开发分支重新设计整个rewrite模块。然后所有事会被改变。
P.S. 此文最早是发表在nginx邮件列表中的:http://forum.nginx.org/read.php?2,174917
0 0
- 【译】Nginx的if是如何工作的(How nginx "location if" works )By agentzh
- 比较两个整数的大小,不能使用 "if", "?:", "switch" 等
- "不要自己发明轮子"与"了解轮子是如何发明的"
- "不要自己发明轮子"与"了解轮子是如何发明的"
- agentzh 的 Nginx 教程 ---笔记
- "不公平"是如何毁掉一个人的生活
- [nginx] if、rewrite、location指令
- 浏览器是如何工作的 - How Browser works
- 浏览器是如何工作的 - How Browser works(一)
- 浏览器是如何工作的 - How Browser works(二)
- 浏览器是如何工作的 - How Browser works(三)
- 浏览器是如何工作的 - How Browser works(四)
- jQuery入门:jQuery是如何工作的 How jQuery Works
- "抱怨"的人永远是"打工"的命
- 成为"天才"的必要条件是"刻意练习"…
- Java中class是如何加载到JVM中的(Class.forName("name")和ClassLoader.loadClass("name")的区别)
- "git rm" 和 "rm" 的区别
- 解放QA的唯一途径是"干掉"QA
- 【转】hbase导出工具Export介绍
- 【转】修改hadoop的备份系数dfs.replication
- Java不同压缩算法的性能比较
- 【转 】Hadoop datanode添加与删除
- 【转】hadoop 添加删除datanode及tasktracker
- 【译】Nginx的if是如何工作的(How nginx "location if" works )By agentzh
- 路由表的优先原则
- 【转】Nginx关闭日志
- JavaScript - 解析JSON
- 关于邮政与高校合作管理的一些个人想法
- 程序打包
- 【转】支付宝代志远:HBase系统故障恢复的优化实践分享
- 【转】通过HBaseAdmin的move方法来迁移Region
- C++ 命名空间