<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    Nginx 變量漫談(四)

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    在設置了“取處理程序”的情況下,Nginx 變量也可以選擇將其值容器用作緩存,這樣在多次讀取變量的時候,就只需要調用“取處理程序”計算一次。我們下面就來看一個這樣的例子:

        map $args $foo {
            default     0;
            debug       1;
        }
     
        server {
            listen 8080;
     
            location /test {
                set $orig_foo $foo;
                set $args debug;
     
                echo "orginal foo: $orig_foo";
                echo "foo: $foo";
            }
        }

    這里首次用到了標準 ngx_map 模塊的 map 配置指令,我們有必要在此介紹一下。map 在英文中除了“地圖”之外,也有“映射”的意思。比方說,中學數學里講的“函數”就是一種“映射”。而 Nginx 的這個 map 指令就可以用于定義兩個 Nginx 變量之間的映射關系,或者說是函數關系。回到上面這個例子,我們用 map 指令定義了用戶變量 $foo 與 $args 內建變量之間的映射關系。特別地,用數學上的函數記法 y = f(x) 來說,我們的$args 就是“自變量” x,而 $foo 則是“因變量” y,即 $foo 的值是由 $args 的值來決定的,或者按照書寫順序可以說,我們將 $args 變量的值映射到了 $foo 變量上。

     

        現在我們再來看 map 指令定義的映射規則:

        map $args $foo {
            default     0;
            debug       1;
        }

    花括號中第一行的 default 是一個特殊的匹配條件,即當其他條件都不匹配的時候,這個條件才匹配。當這個默認條件匹配時,就把“因變量” $foo 映射到值 0. 而花括號中第二行的意思是說,如果“自變量” $args精確匹配了 debug 這個字符串,則把“因變量” $foo 映射到值 1. 將這兩行合起來,我們就得到如下完整的映射規則:當 $args 的值等于 debug 的時候,$foo 變量的值就是 1,否則 $foo 的值就為 0.

     

        明白了 map 指令的含義,再來看 location /test. 在那里,我們先把當前 $foo 變量的值保存在另一個用戶變量 $orig_foo 中,然后再強行把 $args 的值改寫為 debug,最后我們再用 echo 指令分別輸出 $orig_foo和 $foo 的值。

     

        從邏輯上看,似乎當我們強行改寫 $args 的值為 debug 之后,根據先前的 map 映射規則,$foo 變量此時的值應當自動調整為字符串 1, 而不論 $foo 原先的值是怎樣的。然而測試結果并非如此:

        $ curl 'http://localhost:8080/test'
        original foo: 0
        foo: 0

    第一行輸出指示 $orig_foo 的值為 0,這正是我們期望的:上面這個請求并沒有提供 URL 參數串,于是 $args最初的取值就是空,再根據我們先前定義的映射規則,$foo 變量在第一次被讀取時的值就應當是 0(即匹配默認的那個 default 條件)。

     

        而第二行輸出顯示,在強行改寫 $args 變量的值為字符串 debug 之后,$foo 的條件仍然是 0 ,這顯然不符合映射規則,因為當 $args 為 debug 時,$foo 的值應當是 1. 這究竟是為什么呢?

     

        其實原因很簡單,那就是 $foo 變量在第一次讀取時,根據映射規則計算出的值被緩存住了。剛才我們說過,Nginx 模塊可以為其創建的變量選擇使用值容器,作為其“取處理程序”計算結果的緩存。顯然,ngx_map模塊認為變量間的映射計算足夠昂貴,需要自動將因變量的計算結果緩存下來,這樣在當前請求的處理過程中如果再次讀取這個因變量,Nginx 就可以直接返回緩存住的結果,而不再調用該變量的“取處理程序”再行計算了。

     

        為了進一步驗證這一點,我們不妨在請求中直接指定 URL 參數串為 debug:

        $ curl 'http://localhost:8080/test?debug'
        original foo: 1
        foo: 1

    我們看到,現在 $orig_foo 的值就成了 1,因為變量 $foo 在第一次被讀取時,自變量 $args 的值就是debug,于是按照映射規則,“取處理程序”計算返回的值便是 1. 而后續再讀取 $foo 的值時,就總是得到被緩存住的 1 這個結果,而不論 $args 后來變成什么樣了。

     

        map 指令其實是一個比較特殊的例子,因為它可以為用戶變量注冊“取處理程序”,而且用戶可以自己定義這個“取處理程序”的計算規則。當然,此規則在這里被限定為與另一個變量的映射關系。同時,也并非所有使用了“取處理程序”的變量都會緩存結果,例如我們前面在 (三) 中已經看到 $arg_XXX 并不會使用值容器進行緩存。

     

        類似 ngx_map 模塊,標準的 ngx_geo 等模塊也一樣使用了變量值的緩存機制。

     

        在上面的例子中,我們還應當注意到 map 指令是在 server 配置塊之外,也就是在最外圍的 http 配置塊中定義的。很多讀者可能會對此感到奇怪,畢竟我們只是在 location /test 中用到了它。這倒不是因為我們不想把 map 語句直接挪到 location 配置塊中,而是因為 map 指令只能在 http 塊中使用!

     

        很多 Nginx 新手都會擔心如此“全局”范圍的 map 設置會讓訪問所有虛擬主機的所有 location 接口的請求都執行一遍變量值的映射計算,然而事實并非如此。前面我們已經了解到 map 配置指令的工作原理是為用戶變量注冊 “取處理程序”,并且實際的映射計算是在“取處理程序”中完成的,而“取處理程序”只有在該用戶變量被實際讀取時才會執行(當然,因為緩存的存在,只在請求生命期中的第一次讀取中才被執行),所以對于那些根本沒有用到相關變量的請求來說,就根本不會執行任何的無用計算。

     

        這種只在實際使用對象時才計算對象值的技術,在計算領域被稱為“惰性求值”(lazy evaluation)。提供“惰性求值” 語義的編程語言并不多見,最經典的例子便是 Haskell. 與之相對的便是“主動求值” (eager evaluation)。我們有幸在 Nginx 中也看到了“惰性求值”的例子,但“主動求值”語義其實在 Nginx 里面更為常見,例如下面這行再普通不過的 set 語句:

        set $b "$a,$a";

    這里會在執行 set 規定的賦值操作時,“主動”地計算出變量 $b 的值,而不會將該求值計算延緩到變量 $b實際被讀取的時候。

     

        (未完待續)

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全