nginx變量
說明
- 看了好多介紹nginx變量和配置的部落格,春哥寫的太好了,雖然春哥說了不要讀者轉載,文章内容很多,我簡單的寫出了一部分自己覺的好的,以後會經常用的寫下來,例子也會都測試一下,反正沒人會看,萬一被人看到,這裡是春哥的原作位址:春哥的新浪部落格 和春哥維護的OpenResty官網書的位址
nginx變量簡介
Nginx的配置檔案使用的就是一門微型的程式設計語言,變量說白了就是存放“值”的容器。而所謂“值”,在許多程式設計語言裡,既可以是3.14這樣的數值,也可以是 hello world 這樣的字元串,甚至可以是像數組、哈希表這樣的複雜資料結構。然而,在 Nginx 配置中,變量隻能存放一種類型的值,因為也隻存在一種類型的值,那就是字元串。
set $a "hello world";
标準 ngx_rewrite 子產品的 set 配置指令對變量 $a 進行了指派操作 -- set指令在什麼階段
所有的 Nginx 變量在 Nginx 配置檔案中引用時都須帶上 $ 字首,直接把變量嵌入到字元串常量中以構造出新的字元串:
Perl的變量插值
-
變量插值(Perl)
這樣一段程式
$tt="123"
print 'this is $tt.';
結果将列印出
this is $tt.
如果将第二句改成
print "this is $tt.";
也就是把單引号改成雙引号
結果就會列印出
this is 123.
這是因為在使用雙引号時,perl将檢查引号内的每個字元,看看是否有特殊定義, 然後将它替換為其内容,這叫做變量插值。而對于單引号,則原封不動的保持引号 間的内容,不做任何替換。查找了資料之後發現,這裡的變量插值和lua的變量替換相似,
set $a hello;
set $b "$a, $a";
通過已有的 Nginx 變量 $a 的值,來構造變量 $b 的值,于是這兩條指令“順序執行”完之後,$a 的值是 hello,而 $b 的值則是 hello, hello. 這種技術在 Perl 世界裡被稱為“變量插值”(variable interpolation),它讓專門的“字元串拼接運算符”變得不再那麼必要。 想通過 echo 指令直接輸出含有“美元符”($)的字元串,那麼有沒有辦法把特殊的 $ 字元給轉義掉呢?答案是否定的
geo $dollar {
default "$";
}
server {
listen 8080;
location /test {
echo "This is a dollar sign: $dollar";
}
}
我的了解:其他子產品會發生變量替換,但是geo子產品不會發生變量替換。并不是說geo子產品的重要,隻是表名,除非使用特殊的非“變量插值”子產品,一般都要發生變量替換。
geo子產品的作用
ngx_geo 子產品最正常的用法是根據用戶端的 IP 位址對指定的 Nginx 變量進行指派,這裡隻是借用它以便“無條件地”對我們的 $dollar 變量賦予“美元符”這個值。
在“變量插值”的上下文中,還有一種特殊情況,即當引用的變量名之後緊跟着變量名的構成字元時(比如後跟字母、數字以及下劃線),我們就需要使用特别的記法來消除歧義,例如: -- 會出現歧義
server {
listen 8080;
location /test {
set $first "hello "; -- hello無論加不加引号都行
echo "${first}world"; -- 加空格也行
} --看字了解有點煩,看程式好多了
}
這裡,我們在 echo 配置指令的參數值中引用變量 $first 的時候,後面緊跟着 world 這個單詞,是以如果直接寫作 "$firstworld" 則 Nginx “變量插值”計算引擎會将之識别為引用了變量 $firstworld. 為了解決這個難題,Nginx 的字元串記法支援使用花括号在 $ 之後把變量名圍起來,比如這裡的 ${first}. 上面這個例子的輸出是:
$ curl 'http://localhost:8080/test
hello world --輸出,不會出現¥firstworld ,會報錯
set 指令(以及前面提到的 geo 指令)不僅有指派的功能,它還有建立 Nginx 變量的副作用,即當作為指派對象的變量尚不存在時,它會自動建立該變量
nginx變量的用法
Nginx 變量的建立和指派操作發生在全然不同的時間階段。Nginx 變量的建立隻能發生在 Nginx 配置加載的時候,或者說 Nginx 啟動的時候;而指派操作則隻會發生在請求實際處理的時候。這意味着不建立而直接使用變量會導緻啟動失敗,同時也意味着我們無法在請求處理時動态地建立新的 Nginx 變量。我們無法在請求處理時動态地建立新的 Nginx 變量。
-
nginx變量中加不加引号都行,假如自己的了解:
--結果為$a hello; echo $a world;
如果hello world
$a [hello]; echo $a world;
--結果為[hello] world,()等都可以,但是{}确是不可以
Nginx 變量名的可見範圍雖然是整個配置,但每個請求都有所有變量的獨立副本,或者說都有各變量用來存放值的容器的獨立副本,彼此互不幹擾。比如前面我們請求了
接口後,/bar
變量被賦予了值$foo
,但它絲毫不會影響後續對32
接口的請求所對應的/foo
值(它仍然是空的!),因為各個請求都有自己獨立的$foo
$foo
變量的副本。
Nginx 變量了解成某種在請求之間全局共享的東西,或者說“全局變量”。而事實上,Nginx 變量的生命期是不可能跨越請求邊界的
server {
listen 8080;
location /foo {
echo "foo = [$foo]";
}
location /bar {
set $foo 32;
echo "foo = [$foo]";
}
}
這裡我們在
location /bar
中用
set
指令建立了變量
$foo
,于是在整個配置檔案中這個變量都是可見的,是以我們可以在
location /foo
中直接引用這個變量而不用擔心 Nginx 會報錯。
下面是在指令行上用
curl
工具通路這兩個接口的結果:
$ curl ‘http://localhost:8080/foo’
foo = []
$ curl 'http://localhost:8080/bar'
foo = [32]
$ curl 'http://localhost:8080/foo'
foo = []
變量容器的生命期,是與 location 配置塊綁定的。其實不然。我們來看一個涉及“内部跳轉”的例子.
發起到 location /bar 的“内部跳轉”。所謂“内部跳轉”,就是在處理請求的過程中,于伺服器内部,從一個 location 跳轉到另一個 location 的過程。
後者是由 HTTP 用戶端配合進行跳轉的,而且在用戶端,使用者可以通過浏覽器位址欄這樣的界面。
server {
listen 8080;
location /foo {
set $a hello;
echo_exec /bar; -- 子產品的内部跳轉,從一個location- 到另一個location
}
location /bar {
echo "a = [$a]";
}
}
第三方子產品 ngx_echo 提供的 echo_exec 配置指令,後者是由 HTTP 用戶端配合進行跳轉的,而且在用戶端。内部跳轉和 Bourne Shell(或 Bash)中的 exec 指令很像,都是“有去無回”。另一個相近的例子是 C 語言中的 goto 語句。