太棒了
變數漫談(三)" rel="noopener noreferrer">nginx 變數漫談(三)
agentzh
也有一些內建變數是支援改寫的,其中乙個例子是 $args. 這個變數在讀取時返回當前請求的 url 引數串(即請求 url 中問號後面的部分,如果有的話 ),而在賦值時可以直接修改引數串。我們來看乙個例子:
location
/test
這裡我們把原始的 url 引數串先儲存在$orig_args
變數中,然後通過改寫 $args 變數來修改當前的 url 引數串,最後我們用 echo 指令分別輸出$orig_args
和 $args 變數的值。接下來我們這樣來測試這個/test
介面:
在第一次測試中,我們沒有設定任何 url 引數串,所以輸出$orig_args
變數的值時便得到空。而在第一次和第二次測試中,無論我們是否提供 url 引數串,引數串都會在location /test
中被強行改寫成a=3&b=4
.
需要特別指出的是,這裡的 $args 變數和 $arg_*** 一樣,也不再使用屬於自己的存放值的容器。當我們讀取 $args 時,nginx 會執行一小段**,從 nginx 核心中專門存放當前 url 引數串的位置去讀取資料;而當我們改寫 $args 時,nginx 會執行另一小段**,對相同位置進行改寫。nginx 的其他部分在需要當前 url 引數串的時候,都會從那個位置去讀資料,所以我們對 $args 的修改會影響到所有部分的功能。我們來看乙個例子:
location
/test
這裡我們先把內建變數$arg_a
的值,即原始請求的 url 引數a
的值,儲存在使用者變數$orig_a
中,然後通過對內建變數 $args 進行賦值,把當前請求的引數串改寫為a=5
,最後再用 echo 指令分別輸出$orig_a
和$arg_a
變數的值。因為對內建變數 $args 的修改會直接導致當前請求的 url 引數串發生變化,因此內建變數 $arg_*** 自然也會隨之變化。測試的結果證實了這一點:
我們看到,因為原始請求的 url 引數串是a=3
, 所以$arg_a
最初的值為3
, 但隨後通過改寫 $args 變數,將 url 引數串又強行修改為a=5
, 所以最終$arg_a
的值又自動變為了5
.
我們再來看乙個通過修改$args
變數影響標準的 http **模組 ngx_proxy 的例子:
server
}server
}
這裡我們在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
介面:
我們看到,雖然請求自己提供了 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
using namespace std;
class person
void set_name(const string name)
private:
string m_name;
};
在這個名叫person
的 c++ 類中,我們提供了get_name
和set_name
這兩個公共方法,以作為私有成員變數m_name
的「訪問器」。
這樣設計的好處是顯而易見的。類的設計者可以在「訪問器」中執行任意**,以實現所需的業務邏輯以及「***」,比如自動更新與當前成員變數存在依賴關係的其他成員變數,抑或是直接修改某個與當前物件相關聯的資料庫表中的對應字段。而對於後一種情況,也許「訪問器」所對應的成員變數壓根就不存在,或者即使存在,也頂多扮演著資料快取的角色,以緩解被**資料庫的訪問壓力。
與物件導向程式設計中的「訪問器」概念相對應,nginx 變數也是支援繫結「訪問處理程式」的。nginx 模組在建立變數時,可以選擇是否為變數分配存放值的容器,以及是否自己提供與讀寫操作相對應的「訪問處理程式」。
不是所有的 nginx 變數都擁有存放值的容器。擁有值容器的變數在 nginx 核心中被稱為「被索引的」(indexed);反之,則被稱為「未索引的」(non-indexed)。
我們前面在 (二) 中已經知道,像 $arg_*** 這樣具有無數變種的變數群,是「未索引的」。當讀取這樣的變數時,其實是它的「取處理程式」在起作用,即實時掃瞄當前請求的 url 引數串,提取出變數名所指定的 url 引數的值。很多新手都會對 $arg_*** 的實現方式產生誤解,以為 nginx 會事先解析好當前請求的所有 url 引數,並且把相關的 $arg_*** 變數的值都事先設定好。然而事實並非如此,nginx 根本不會事先就解析好 url 引數串,而是在使用者讀取某個 $arg_*** 變數時,呼叫其「取處理程式」,即時去掃瞄 url 引數串。類似地,內建變數 $cookie_*** 也是通過它的「取處理程式」,即時去掃瞄cookie
請求頭中的相關定義的。
(未完待續)
Nginx 變數漫談(六)
nginx 內建變數用在 子請求 的上下文中時,其行為也會變得有些微妙。前面在 三 中我們已經知道,許多內建變數都不是簡單的 存放值的容器 它們一般會通過註冊 訪問處理程式 來表現得與眾不同,而它們即使有存放值的容器,也只是用於快取 訪問處理程式 的計算結果。我們之前討論過的 args 變數正是通過...
Nginx 變數漫談(四)
在設定了 取處理程式 的情況下,nginx 變數也可以選擇將其值容器用作快取,這樣在多次讀取變數的時候,就只需要呼叫 取處理程式 計算一次。我們下面就來看乙個這樣的例子 map args foo server 這裡首次用到了標準 ngx map 模組的 map 配置指令,我們有必要在此介紹一下。ma...
Nginx 變數漫談(八)
與 arg 類似,我們在 二 中提到過的內建變數 cookie 變數也會在名為 的 cookie 不存在時返回特殊值 沒找到 location test 利用curl命令列工具的 cookie name value選項可以指定name value為當前請求攜帶的 cookie 通過新增相應的cook...