<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系統、金蝶與條碼系統對接、用友與條碼系統對接

    也有一些內建變量是支持改寫的,其中一個例子是 $args. 這個變量在讀取時返回當前請求的 URL 參數串(即請求 URL 中問號后面的部分,如果有的話 ),而在賦值時可以直接修改參數串。我們來看一個例子:

        location /test {
            set $orig_args $args;
            set $args "a=3&b=4";
     
            echo "original args: $orig_args";
            echo "args: $args";
        }

    這里我們把原始的 URL 參數串先保存在 $orig_args 變量中,然后通過改寫 $args 變量來修改當前的 URL 參數串,最后我們用 echo 指令分別輸出 $orig_args 和 $args 變量的值。接下來我們這樣來測試這個 /test 接口:

        $ curl 'http://localhost:8080/test'
        original args: 
        args: a=3&b=4
     
        $ curl 'http://localhost:8080/test?a=0&b=1&c=2'
        original args: a=0&b=1&c=2
        args: a=3&b=4

    在第一次測試中,我們沒有設置任何 URL 參數串,所以輸出 $orig_args 變量的值時便得到空。而在第一次和第二次測試中,無論我們是否提供 URL 參數串,參數串都會在 location /test 中被強行改寫成 a=3&b=4.

     

        需要特別指出的是,這里的 $args 變量和 $arg_XXX 一樣,也不再使用屬于自己的存放值的容器。當我們讀取 $args 時,Nginx 會執行一小段代碼,從 Nginx 核心中專門存放當前 URL 參數串的位置去讀取數據;而當我們改寫 $args 時,Nginx 會執行另一小段代碼,對相同位置進行改寫。Nginx 的其他部分在需要當前 URL 參數串的時候,都會從那個位置去讀數據,所以我們對 $args 的修改會影響到所有部分的功能。我們來看一個例子:

        location /test {
            set $orig_a $arg_a;
            set $args "a=5";
            echo "original a: $orig_a";
            echo "a: $arg_a";
        }

    這里我們先把內建變量 $arg_a 的值,即原始請求的 URL 參數 a 的值,保存在用戶變量 $orig_a 中,然后通過對內建變量 $args 進行賦值,把當前請求的參數串改寫為 a=5 ,最后再用 echo 指令分別輸出 $orig_a 和$arg_a 變量的值。因為對內建變量 $args 的修改會直接導致當前請求的 URL 參數串發生變化,因此內建變量$arg_XXX 自然也會隨之變化。測試的結果證實了這一點:

        $ curl 'http://localhost:8080/test?a=3'
        original a: 3
        a: 5

    我們看到,因為原始請求的 URL 參數串是 a=3, 所以 $arg_a 最初的值為 3, 但隨后通過改寫 $args 變量,將 URL 參數串又強行修改為 a=5, 所以最終 $arg_a 的值又自動變為了 5.

     

        我們再來看一個通過修改 $args 變量影響標準的 HTTP 代理模塊 ngx_proxy 的例子:

        server {
            listen 8080;
     
            location /test {
                set $args "foo=1&bar=2";
                proxy_pass http://127.0.0.1:8081/args;
            }
        }
     
        server {
            listen 8081;
     
            location /args {
                echo "args: $args";
            }
        }

    這里我們在 http 配置塊中定義了兩個虛擬主機。第一個虛擬主機監聽 8080 端口,其 /test 接口自己通過改寫 $args 變量,將當前請求的 URL 參數串無條件地修改為 foo=1&bar=2. 然后 /test 接口再通過 ngx_proxy模塊的 proxy_pass 指令配置了一個反向代理,指向本機的 8081 端口上的 HTTP 服務 /args. 默認情況下,ngx_proxy 模塊在轉發 HTTP 請求到遠方 HTTP 服務的時候,會自動把當前請求的 URL 參數串也轉發到遠方。

     

        而本機的 8081 端口上的 HTTP 服務正是由我們定義的第二個虛擬主機來提供的。我們在第二個虛擬主機的location /args 中利用 echo 指令輸出當前請求的 URL 參數串,以檢查 /test 接口通過 ngx_proxy 模塊實際轉發過來的 URL 請求參數串。

     

        我們來實際訪問一下第一個虛擬主機的 /test 接口:

        $ curl 'http://localhost:8080/test?blah=7'
        args: foo=1&bar=2

    我們看到,雖然請求自己提供了 URL 參數串 blah=7,但在 location /test 中,參數串被強行改寫成了foo=1&bar=2. 接著經由 proxy_pass 指令將我們被改寫掉的參數串轉發給了第二個虛擬主機上配置的 /args 接口,然后再把 /args 接口的 URL 參數串輸出。事實證明,我們對 $args 變量的賦值操作,也成功影響到了ngx_proxy 模塊的行為。

     

        在讀取變量時執行的這段特殊代碼,在 Nginx 中被稱為“取處理程序”(get handler);而改寫變量時執行的這段特殊代碼,則被稱為“存處理程序”(set handler)。不同的 Nginx 模塊一般會為它們的變量準備不同的“存取處理程序”,從而讓這些變量的行為充滿魔法。

     

        其實這種技巧在計算世界并不鮮見。比如在面向對象編程中,類的設計者一般不會把類的成員變量直接暴露給類的用戶,而是另行提供兩個方法(method),分別用于該成員變量的讀操作和寫操作,這兩個方法常常被稱為“存取器”(accessor)。下面是 C++ 語言中的一個例子:

        #include <string>
        using namespace std;
     
        class Person {
        public:
            const string get_name() {
                return m_name;
            }
     
            void set_name(const string name) {
                m_name = name;
            }
     
        private:
            string m_name;
        };

    在這個名叫 Person 的 C++ 類中,我們提供了 get_name 和 set_name 這兩個公共方法,以作為私有成員變量m_name 的“存取器”。

     

        這樣設計的好處是顯而易見的。類的設計者可以在“存取器”中執行任意代碼,以實現所需的業務邏輯以及“副作用”,比如自動更新與當前成員變量存在依賴關系的其他成員變量,抑或是直接修改某個與當前對象相關聯的數據庫表中的對應字段。而對于后一種情況,也許“存取器”所對應的成員變量壓根就不存在,或者即使存在,也頂多扮演著數據緩存的角色,以緩解被代理數據庫的訪問壓力。

     

        與面向對象編程中的“存取器”概念相對應,Nginx 變量也是支持綁定“存取處理程序”的。Nginx 模塊在創建變量時,可以選擇是否為變量分配存放值的容器,以及是否自己提供與讀寫操作相對應的“存取處理程序”。

     

        不是所有的 Nginx 變量都擁有存放值的容器。擁有值容器的變量在 Nginx 核心中被稱為“被索引的”(indexed);反之,則被稱為“未索引的”(non-indexed)。

     

        我們前面在 (二) 中已經知道,像 $arg_XXX 這樣具有無數變種的變量群,是“未索引的”。當讀取這樣的變量時,其實是它的“取處理程序”在起作用,即實時掃描當前請求的 URL 參數串,提取出變量名所指定的 URL 參數的值。很多新手都會對 $arg_XXX 的實現方式產生誤解,以為 Nginx 會事先解析好當前請求的所有 URL 參數,并且把相關的 $arg_XXX 變量的值都事先設置好。然而事實并非如此,Nginx 根本不會事先就解析好 URL 參數串,而是在用戶讀取某個 $arg_XXX 變量時,調用其“取處理程序”,即時去掃描 URL 參數串。類似地,內建變量 $cookie_XXX 也是通過它的“取處理程序”,即時去掃描 Cookie 請求頭中的相關定義的。

     

        (未完待續)

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