Nginx 變量漫談(八)
與 $arg_XXX 類似,我們在 (二) 中提到過的內建變量 $cookie_XXX 變量也會在名為 XXX
的 cookie 不存在時返回特殊值“沒找到”:
location /test {
content_by_lua '
if ngx.var.cookie_user == nil then
ngx.say("cookie user: missing")
else
ngx.say("cookie user: [", ngx.var.cookie_user, "]")
end
';
}
利用 curl
命令行工具的 --cookie name=value
選項可以指定 name=value
為當前請求攜帶的 cookie(通過添加相應的 Cookie
請求頭)。下面是若干次測試結果:
$ curl --cookie user=agentzh 'http://localhost:8080/test'
cookie user: [agentzh]
$ curl --cookie user= 'http://localhost:8080/test'
cookie user: []
$ curl 'http://localhost:8080/test'
cookie user: missing
我們看到,cookie user
不存在以及取值為空字符串這兩種情況被很好地區分開了:當 cookie user
不存在時,Lua 代碼中的 ngx.var.cookie_user
返回了期望的 Lua nil
值。
在 Lua 里訪問未創建的 Nginx 用戶變量時,在 Lua 里也會得到 nil
值,而不會像先前的例子那樣直接讓 Nginx 拒絕加載配置:
location /test {
content_by_lua '
ngx.say("$blah = ", ngx.var.blah)
';
}
這里假設我們并沒有在當前的 nginx.conf
配置文件中創建過用戶變量 $blah
,然后我們在 Lua 代碼中通過ngx.var.blah
直接引用它。上面這個配置可以順利啟動,因為 Nginx 在加載配置時只會編譯 content_by_lua配置指令指定的 Lua 代碼而不會實際執行它,所以 Nginx 并不知道 Lua 代碼里面引用了 $blah
這個變量。于是我們在運行時也會得到 nil
值。而 ngx_lua 提供的 ngx.say 函數會自動把 Lua 的 nil
值格式化為字符串"nil"
輸出,于是訪問 /test
接口的結果是:
curl 'http://localhost:8080/test'
$blah = nil
這正是我們所期望的。
上面這個例子中另一個值得注意的地方是,我們在 content_by_lua 配置指令的參數中提及了 $bar
符號,但卻并沒有觸發“變量插值”(否則 Nginx 會在啟動時抱怨 $blah
未創建)。這是因為 content_by_lua 配置指令并不支持參數的“變量插值”功能。我們前面在 (一) 中提到過,配置指令的參數是否允許“變量插值”,其實取決于該指令的實現模塊。
設計返回“不合法”這一特殊值的例子是困難的,因為我們前面在 (七) 中已經看到,由 set 指令創建的變量在未初始化時確實是“不合法”,但一旦嘗試讀取它們時,Nginx 就會自動調用其“取處理程序”,而它們的“取處理程序”會自動返回空字符串并將之緩存住。于是我們最終得到的是完全合法的空字符串。下面這個使用了 Lua 代碼的例子證明了這一點:
location /foo {
content_by_lua '
if ngx.var.foo == nil then
ngx.say("$foo is nil")
else
ngx.say("$foo = [", ngx.var.foo, "]")
end
';
}
location /bar {
set $foo 32;
echo "foo = [$foo]";
}
請求 /foo
接口的結果是:
$ curl 'http://localhost:8080/foo'
$foo = []
我們看到在 Lua 里面讀取未初始化的 Nginx 變量 $foo
時得到的是空字符串。
最后值得一提的是,雖然前面反復指出 Nginx 變量只有字符串這一種數據類型,但這并不能阻止像ngx_array_var 這樣的第三方模塊讓 Nginx 變量也能存放數組類型的值。下面就是這樣的一個例子:
location /test {
array_split "," $arg_names to=$array;
array_map "[$array_it]" $array;
array_join " " $array to=$res;
echo $res;
}
這個例子中使用了 ngx_array_var 模塊的 array_split
、 array_map
和 array_join
這三條配置指令,其含義很接近 Perl 語言中的內建函數 split
、map
和 join
(當然,其他腳本語言也有類似的等價物)。我們來看看訪問 /test
接口的結果:
$ curl 'http://localhost:8080/test?names=Tom,Jim,Bob
[Tom] [Jim] [Bob]
我們看到,使用 ngx_array_var 模塊可以很方便地處理這樣具有不定個數的組成元素的輸入數據,例如此例中的 names
URL 參數值就是由不定個數的逗號分隔的名字所組成。不過,這種類型的復雜任務通過 ngx_lua 來做通常會更靈活而且更容易維護。
至此,本系列教程對 Nginx 變量的介紹終于可以告一段落了。我們在這個過程中接觸到了許多標準的和第三方的 Nginx 模塊,這些模塊讓我們得以很輕松地構造出許多有趣的小例子,從而可以深入探究 Nginx 變量的各種行為和特性。在后續的教程中,我們還會有很多機會與這些模塊打交道。
通過前面討論過的眾多例子,我們應當已經感受到 Nginx 變量在 Nginx 配置語言中所扮演的重要角色:它是獲取 Nginx 中各種信息(包括當前請求的信息)的主要途徑和載體,同時也是各個模塊之間傳遞數據的主要媒介之一。在后續的教程中,我們會經常看到 Nginx 變量的身影,所以現在很好地理解它們是非常重要的。
在下一個系列的教程,即 Nginx 配置指令的執行順序系列 中,我們將深入探討 Nginx 配置指令的執行順序以及請求的各個處理階段,因為很多 Nginx 用戶都搞不清楚他們書寫的眾多配置指令之間究竟是按照何種時間順序執行的,也搞不懂為什么這些指令實際執行的順序經常和配置文件里的書寫順序大相徑庭。
RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成