`
邢邢色色
  • 浏览: 230535 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

【译】Nginx的if是如何工作的(How nginx "location if" works )By agentzh

阅读更多

出处:

去年我写过一篇英文的:
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
分享到:
评论

相关推荐

    agentzh写的Nginx教程

    9. 作者的背景:agentzh在过去的几年里在Nginx领域做了很多工作,致力于分享他所完成的工作和学到的知识。 10. 文章发布平台:教程系列文章将发布在新浪博客上,网址为***,并且是用中文发布的。 11. 未来计划:...

    agentzh nginx教程

    agentzh nginx教程 

    agentzh 的 Nginx 教程(版本 2016.07.21) pdf与htm打包

    《agentzh的Nginx教程(版本2016.07.21)》是一部由知名开源社区成员agentzh编写的Nginx技术指南,它涵盖了Nginx的广泛主题,包括基础配置、模块开发、性能优化以及高级用法。这个教程的特色在于其详尽的内容和对...

    Nginx中if语句的判断条件与多条件判断详解

    一、if语句中的判断条件(nginx)介绍 1、正则表达式匹配:  ==:等值比较;  ~:与指定正则表达式模式匹配时返回“真”,判断匹配与否时区分字符大小写;  ~*:与指定正则表达式模式匹配时返回“真”,判断匹配...

    agentzh-nginx-tutorials-zhcn.mobi

    熟悉 Perl、Bourne Shell、C/C++ 等命令式编程语言的朋友肯定知道,变量说白了就是存放“值”的容器。而所谓“值”,在许多编程... agentzh的Nginx教程(2016.07.21版) (Kindle 位置 66-70). agentzh. Kindle 版本.

    agentzh 的 Nginx 教程(版本 2016.07.21

    - **Nginx的if是邪恶的**:讨论了Nginx中if指令的局限性和替代方案,鼓励开发者采用更高效的方式实现条件逻辑。 - **Nginx子请求**:介绍了子请求的概念及其在负载均衡、缓存策略等方面的用途。 - **Nginx静态文件...

    agentzh 的 Nginx 教程(版本 2016.07.21)整理成pdf 添加书签

    - **作者背景**:作者章亦春(agentzh)希望通过一系列的文章分享其在Nginx领域的经验和知识。 - **发布平台**:选择在新浪博客(http://blog.sina.com.cn/openresty)上发布这些教程。 - **组织形式**:教程以系列...

    agentzh-nginx-tutorials-zhcn.pdf

    ### Nginx教程知识点概述 ...以上知识点涵盖了《agentzh-nginx-tutorials-zhcn.pdf》文档中提及的主要技术要点,通过学习这些内容,读者可以深入了解Nginx的强大功能及其在实际应用场景中的灵活运用。

    nginx location中多个if里面proxy_pass的方法

    在Nginx配置中,`...总之,理解Nginx `location`的匹配机制和`if`语句的使用是优化Web服务器配置的关键。正确地利用这些特性,可以根据URL、参数等条件灵活地控制请求的处理流程,实现高效的负载均衡和内容分发。

    agentzh-nginx-tutorials-en.pdf

    作者在过去几年中深入参与了Nginx相关工作,并决定将这些经验和知识通过中文博客的形式分享出来。文档分为多个系列,每个系列可以视为未来可能出版的Nginx书籍中的一个章节。本文主要关注的是Nginx变量与指令执行...

    agentzh 的 Nginx 教程(版本 2019.05.08)openresty 电子书

    这份教程名为《agentzh 的 Nginx 教程(版本 2019.05.08)》,作者是章亦春,也叫agentzh,是一名活跃在 Nginx 相关技术社区的专家。该教程提供了深入浅出的 Nginx 使用指南,囊括了 Nginx 基础知识以及高级特性,...

    nginx配置location时容易出现的误区

    ### Nginx 配置 Location 时常见的误区详解 在 Nginx 的配置过程中,`location` 是一个非常重要的概念,用于控制特定 URL 模式的请求处理方式。然而,在实际应用中,不少开发者对 `location` 的理解存在一定的误区...

    Nginx Location 正则_NginxLocation正则.md_

    nginx正则表达式. : 匹配除换行符以外的任意字符? : 重复0次或1次+ : 重复1次或更多次* : 重复0次或更多次\d :匹配数字^ : 匹配字符串的开始$ : 匹配字符串的介绍{n} : 重复n次{n} : 重复n次或更多次[c] :...

    Nginx if语句加正则表达式实现字符串截断

    因此,在使用if语句时需要非常小心,并确保充分理解其工作原理和可能的副作用。 正则表达式(Regular Expression),是一种文本模式,包括普通字符(例如,每个字母或数字)和特殊字符(称为“元字符”)。正则...

    Nginx中IF、AND、OR语句用法实例

    在Nginx配置中,`IF`语句用于执行基于某些条件的逻辑判断,而`AND`和`OR`操作通常在编程语言中用于组合多个条件。然而,Nginx的配置语法并不直接支持`AND`和`OR`操作符。尽管如此,我们可以使用变量和条件语句的组合...

    Nginx 反向代理工作原理简介与配置详解 - 李雄

    本文将深入探讨Nginx反向代理的工作原理,并提供详细的配置教程。 一、Nginx反向代理工作原理 1. 基本概念:反向代理是指客户端请求到达Nginx服务器后,Nginx不直接处理请求,而是将其转发到后端的真实服务器上。...

    nginx中带问号(?) 带参数的rewrite规则

    在Nginx服务器配置中,`rewrite`指令用于URL重写,这在创建动态到静态页面的重定向、实现URL路由、或者根据特定条件改变URL结构时非常有用。当URL中包含问号(`?`)以及参数时,处理起来可能会有些复杂,因为问号及其...

    Nginx反向代理工作原理简介与配置详解-李雄

    本文将深入介绍Nginx反向代理的工作原理,并提供详细的配置步骤。 首先,理解反向代理的概念至关重要。在传统的正向代理中,用户通过代理服务器访问目标网站,代理服务器隐藏了真实用户的IP地址。而在反向代理中,...

    centos8 nginx1.20.1 与nginx配置文件

    WantedBy=multi-user.target ``` 保存并关闭文件,然后启动Nginx服务并设置开机启动: ```bash sudo systemctl start nginx sudo systemctl enable nginx ``` 接下来,我们将配置Nginx以支持HTTPS。你需要准备一对...

Global site tag (gtag.js) - Google Analytics