<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[静怡家园]]></title> 
<link>http://www.zhanghaijun.com/index.php</link> 
<description><![CDATA[书山有路勤为径，学海无涯苦作舟！]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[静怡家园]]></copyright>
<item>
<link>http://www.zhanghaijun.com/post//</link>
<title><![CDATA[nginx变量使用方法详解-4]]></title> 
<author>碟舞飞扬 &lt;webmaster@zhanghaijun.com&gt;</author>
<category><![CDATA[Linux技术]]></category>
<pubDate>Thu, 26 Feb 2009 06:10:07 +0000</pubDate> 
<guid>http://www.zhanghaijun.com/post//</guid> 
<description>
<![CDATA[ 
	在设置了“取处理程序”的情况下，Nginx 变量也可以选择将其值容器用作缓存，这样在多次读取变量的时候，就只需要调用“取处理程序”计算一次。我们下面就来看一个这样的例子：<br/><div class="code"><br/>&nbsp;&nbsp;&nbsp;&nbsp;map $args $foo &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default&nbsp;&nbsp;&nbsp;&nbsp; 0;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;debug&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;server &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;listen 8080;<br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;location /test &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set $orig_foo $foo;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set $args debug;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;orginal foo: $orig_foo&quot;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;foo: $foo&quot;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/></div><br/>这里首次用到了标准 ngx_map 模块的 map 配置指令，我们有必要在此介绍一下。map 在英文中除了“地图”之外，也有“映射”的意思。比方说，中学数学里讲的“函数”就是一种“映射”。而 Nginx 的这个 map 指令就可以用于定义两个 Nginx 变量之间的映射关系，或者说是函数关系。回到上面这个例子，我们用 map 指令定义了用户变量 $foo 与 $args 内建变量之间的映射关系。特别地，用数学上的函数记法 y = f(x) 来说，我们的 $args 就是“自变量” x，而 $foo 则是“因变量” y，即 $foo 的值是由 $args 的值来决定的，或者按照书写顺序可以说，我们将 $args 变量的值映射到了 $foo 变量上。<br/>现在我们再来看 map 指令定义的映射规则：<br/><div class="code"><br/>&nbsp;&nbsp;&nbsp;&nbsp;map $args $foo &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default&nbsp;&nbsp;&nbsp;&nbsp; 0;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;debug&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/></div><br/>花括号中第一行的 default 是一个特殊的匹配条件，即当其他条件都不匹配的时候，这个条件才匹配。当这个默认条件匹配时，就把“因变量” $foo 映射到值 0. 而花括号中第二行的意思是说，如果“自变量” $args 精确匹配了 debug 这个字符串，则把“因变量” $foo 映射到值 1. 将这两行合起来，我们就得到如下完整的映射规则：当 $args 的值等于 debug 的时候，$foo 变量的值就是 1，否则 $foo 的值就为 0.<br/>明白了 map 指令的含义，再来看 location /test. 在那里，我们先把当前 $foo 变量的值保存在另一个用户变量 $orig_foo 中，然后再强行把 $args 的值改写为 debug，最后我们再用 echo 指令分别输出 $orig_foo 和 $foo 的值。<br/>从逻辑上看，似乎当我们强行改写 $args 的值为 debug 之后，根据先前的 map 映射规则，$foo 变量此时的值应当自动调整为字符串 1, 而不论 $foo 原先的值是怎样的。然而测试结果并非如此：<br/><div class="code"><br/>&nbsp;&nbsp;&nbsp;&nbsp;$ curl &#039;http://localhost:8080/test&#039;<br/>&nbsp;&nbsp;&nbsp;&nbsp;original foo: 0<br/>&nbsp;&nbsp;&nbsp;&nbsp;foo: 0<br/></div><br/>第一行输出指示 $orig_foo 的值为 0，这正是我们期望的：上面这个请求并没有提供 URL 参数串，于是 $args 最初的取值就是空，再根据我们先前定义的映射规则，$foo 变量在第一次被读取时的值就应当是 0（即匹配默认的那个 default 条件）。<br/>而第二行输出显示，在强行改写 $args 变量的值为字符串 debug 之后，$foo 的条件仍然是 0 ，这显然不符合映射规则，因为当 $args 为 debug 时，$foo 的值应当是 1. 这究竟是为什么呢？<br/>其实原因很简单，那就是 $foo 变量在第一次读取时，根据映射规则计算出的值被缓存住了。刚才我们说过，Nginx 模块可以为其创建的变量选择使用值容器，作为其“取处理程序”计算结果的缓存。显然，ngx_map 模块认为变量间的映射计算足够昂贵，需要自动将因变量的计算结果缓存下来，这样在当前请求的处理过程中如果再次读取这个因变量，Nginx 就可以直接返回缓存住的结果，而不再调用该变量的“取处理程序”再行计算了。<br/>为了进一步验证这一点，我们不妨在请求中直接指定 URL 参数串为 debug:<br/><div class="code"><br/>&nbsp;&nbsp;&nbsp;&nbsp;$ curl &#039;http://localhost:8080/test?debug&#039;<br/>&nbsp;&nbsp;&nbsp;&nbsp;original foo: 1<br/>&nbsp;&nbsp;&nbsp;&nbsp;foo: 1<br/></div><br/>我们看到，现在 $orig_foo 的值就成了 1，因为变量 $foo 在第一次被读取时，自变量 $args 的值就是 debug，于是按照映射规则，“取处理程序”计算返回的值便是 1. 而后续再读取 $foo 的值时，就总是得到被缓存住的 1 这个结果，而不论 $args 后来变成什么样了。<br/>map 指令其实是一个比较特殊的例子，因为它可以为用户变量注册“取处理程序”，而且用户可以自己定义这个“取处理程序”的计算规则。当然，此规则在这里被限定为与另一个变量的映射关系。同时，也并非所有使用了“取处理程序”的变量都会缓存结果，例如我们前面在 （三） 中已经看到 $arg_XXX 并不会使用值容器进行缓存。<br/>类似 ngx_map 模块，标准的 ngx_geo 等模块也一样使用了变量值的缓存机制。<br/>在上面的例子中，我们还应当注意到 map 指令是在 server 配置块之外，也就是在最外围的 http 配置块中定义的。很多读者可能会对此感到奇怪，毕竟我们只是在 location /test 中用到了它。这倒不是因为我们不想把 map 语句直接挪到 location 配置块中，而是因为 map 指令只能在 http 块中使用！<br/>很多 Nginx 新手都会担心如此“全局”范围的 map 设置会让访问所有虚拟主机的所有 location 接口的请求都执行一遍变量值的映射计算，然而事实并非如此。前面我们已经了解到 map 配置指令的工作原理是为用户变量注册 “取处理程序”，并且实际的映射计算是在“取处理程序”中完成的，而“取处理程序”只有在该用户变量被实际读取时才会执行（当然，因为缓存的存在，只在请求生命期中的第一次读取中才被执行），所以对于那些根本没有用到相关变量的请求来说，就根本不会执行任何的无用计算。<br/>这种只在实际使用对象时才计算对象值的技术，在计算领域被称为“惰性求值”（lazy evaluation）。提供“惰性求值” 语义的编程语言并不多见，最经典的例子便是 Haskell. 与之相对的便是“主动求值” （eager evaluation）。我们有幸在 Nginx 中也看到了“惰性求值”的例子，但“主动求值”语义其实在 Nginx 里面更为常见，例如下面这行再普通不过的 set 语句：<br/><div class="code"><br/>&nbsp;&nbsp;&nbsp;&nbsp;set $b &quot;$a,$a&quot;;<br/></div><br/>这里会在执行 set 规定的赋值操作时，“主动”地计算出变量 $b 的值，而不会将该求值计算延缓到变量 $b 实际被读取的时候。<br/>Tags - <a href="http://www.zhanghaijun.com/tags/nginx/" rel="tag">nginx</a>
]]>
</description>
</item><item>
<link>http://www.zhanghaijun.com/post//#blogcomment</link>
<title><![CDATA[[评论] nginx变量使用方法详解-4]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>http://www.zhanghaijun.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>