詳細原文檢視這裡:http://blog.sina.com.cn/s/blog_6d579ff40100wk2j.html
另一篇歸納原文的文章看這裡:http://blog.csdn.net/yankai0219/article/details/8070790
變量插值:
所有的 Nginx變量在 Nginx配置檔案中引用時都須帶上 $字首,用$符号+變量名來構造新的變量,這種方式叫做變量插值。
例如:
location test{
set $a hello;
set $b "$a ,world";
echo "b: $b";
}
通路: curl http://localhost/test/
輸出:b: hello world
說明:上述set是HttpRewriteModule的指令,而echo是HttpEchoModule指令。可見這兩個子產品都支援變量插值。
但是并不是所有子產品都支援變量插值,事實上,指令參數是否允許“變量插值”,取決于該指令的實作子產品。
變量使用注意點:
當變量後面直接接其他字元串時,需要用{}将變量名括起來,否則會将變量名和後面的字元串連在一起當成一個變量名
例如:
location /test {
set $variable "hello";
echo"${variable}world";
}
變量必須先建立再使用,否則報錯
例如:
server {
listen 80;
location /test
{
echo $foo;
}
}
通路: curl http://localhost/test/
報錯:[emerg] unknown"foo" variable
說明:nginxnginx變量的建立和指派操作發生在全然不同的時間階段。Nginx變量的建立隻能發生在 Nginx配置加載的時候,或者說 Nginx啟動的時候;而指派操作則隻會發生在請求實際處理的時候。這意味着不建立而直接使用變量會導緻啟動失敗,同時也意味着我們無法在請求處理時動态地建立新的 Nginx變量
變量的可見性和作用域:
Nginx 變量一旦建立,其變量名的可見範圍就是整個 Nginx 配置,甚至可以跨越不同虛拟主機的 server 配置塊。
例如:
server {
listen 80;
location /foo {
echo "foo =[$foo]";
}
location /bar {
set $foo 32;
echo "foo =[$foo]";
}
}
說明:這裡我們在 location /bar 中用 set 指令建立了變量 $foo ,于是在整個配置檔案中這個變量都是可見的,是以我們可以在 location /foo 中直接引用這個變量而不用擔心 Nginx 會報錯。
通路這兩個接口的結果:
$ curl 'http://localhost/foo'
foo = []
$ curl 'http://localhost/bar'
foo = [32]
$ curl 'http://localhost/foo'
foo = []
從本例子得出另一個變量特性:
Nginx 變量名的可見範圍雖然是整個配置,但每個請求都有所有變量的獨立副本,或者說都有各變量用來存放值的容器的獨立副本,彼此互不幹擾。
比如前面我們請求了 /bar接口後,$foo變量被賦予了值 32,但它絲毫不會影響後續對 /foo接口的請求所對應的 $foo值(它仍然是空的!),因為各個請求都有自己獨立的 $foo變量的副本
對于 Nginx新手來說,最常見的錯誤之一,就是将 Nginx變量了解成某種在請求之間全局共享的東西,或者說“全局變量”。而事實上,Nginx變量的生命期是不可能跨越請求邊界的
另外一個誤區是:認為變量容器的生命期,是與
l
ocation
配置塊綁定的。其實不然。我們來看一個涉及“内部跳轉”的例子
server {
listen 8080;
location /foo {
set $a hello;
echo_exec /bar;
}
location /bar {
echo "a = [$a]";
}
}
這裡我們在
location /foo
中,使用第三方子產品ngx_echo提供的echo_exec配置指令,發起到
location /bar
的“内部跳轉”。所謂“内部跳轉”,就是在處理請求的過程中,于伺服器内部,從一個
location
跳轉到另一個
location
的過程。這不同于利用 HTTP 狀态碼
301
和
302
所進行的“外部跳轉”,因為後者是由 HTTP 用戶端配合進行跳轉的,而且在用戶端,使用者可以通過浏覽器位址欄這樣的界面,看到請求的 URL 位址發生了變化。内部跳轉和
Bourne Shell
(或
Bash
)中的
exec
指令很像,都是“有去無回”。另一個相近的例子是
C
語言中的
goto
語句。
既然是内部跳轉,目前正在處理的請求就還是原來那個,隻是目前的
location
發生了變化,是以還是原來的那一套 Nginx 變量的容器副本。對應到上例,如果我們請求的是
/foo
這個接口,那麼整個工作流程是這樣的:先在
location /foo
中通過set指令将
$a
變量的值賦為字元串
hello
,然後通過echo_exec指令發起内部跳轉,又進入到
location /bar
中,再輸出
$a
變量的值。因為
$a
還是原來的
$a
,是以我們可以期望得到
hello
這行輸出。測試證明了這一點。
$ curl localhost:8080/foo
a = [hello]
但如果我們從用戶端直接通路
/bar
接口,就會得到空的
$a
變量的值,因為它依賴于
location /foo
來對
$a
進行初始化。
從上面這個例子我們看到,一個請求在其處理過程中,即使經曆多個不同的
location
配置塊,它使用的還是同一套 Nginx 變量的副本。
這裡,我們也首次涉及到了“内部跳轉”這個概念。值得一提的是标準ngx_rewrite子產品的rewrite配置指令其實也可以發起“内部跳轉”,例如上面那個例子用rewrite配置指令可以改寫成下面這樣的形式:
server {
listen 8080;
location /foo {
set $a hello;
rewrite ^ /bar;
}
location /bar {
echo "a = [$a]";
}
}
其效果和使用 echo_exec 是完全相同的。後面我們還會專門介紹這個 rewrite 指令的更多用法,比如發起 301 和 302 這樣的“外部跳轉”。
内建變量
常見的内建變量:
$uri: 用來擷取目前請求的URI(經過解碼,并且不包含請求參數)
$request_uri:用來擷取請求最原始的URI(未經解碼,并且包含請求參數)
location /test {
echo "uri = $uri";
echo "request_uri =$request_uri";
}
請求和響應:
$ curl 'http://localhost:8080/test'
uri = /test
request_uri = /test
$ curl 'http://localhost:8080/test?a=3&b=4'
uri = /test
request_uri = /test?a=3&b=4
$ curl 'http://localhost:8080/test/hello%20world?a=3&b=4'
uri = /test/hello world
request_uri = /test/hello%20world?a=3&b=4
$arg_xxx變量群:用來擷取目前請求名為xxx的URI參數的值
location /test {
echo "name:$arg_name";
echo "class:$arg_class";
}
請求和響應:
$ curl 'http://localhost:8080/test'
name:
class:
$ curl 'http://localhost:8080/test?name=Tom&class=3'
name: Tom
class: 3
$ curl 'http://localhost:8080/test?name=hello%20world&class=9'
name: hello%20world
class: 9
其實 $arg_name不僅可以比對 name參數,也可以比對 NAME參數,抑或是 Name,等等,Nginx會在比對參數名之前,自動把原始請求中的參數名調整為全部小寫的形式:
$ curl 'http://localhost:8080/test?NAME=Marry'
name: Marry
class:
$ curl 'http://localhost:8080/test?Name=Jimmy'
name: Jimmy
class:
$cookie_xxx變量群:用來擷取cookie值
$http_xxx變量群:用來擷取請求頭的值
$send_http_xxx變量群:用來擷取響應頭的值
$args:傳回目前請求的URL參數串(即請求URL中問号後面的部分)
如果你嘗試改寫另外一些隻讀的内建變量,比如 $arg_XXX 變量,在某些 Nginx 的版本中甚至可能導緻程序崩潰。
location /bad {
set $uri /blah;
echo $uri;
}
這個有問題的配置會讓 Nginx 在啟動的時候報出一條令人匪夷所思的錯誤:
[emerg] the duplicate "uri" variable in ...
也有一些内建變量是支援改寫的,其中一個例子是 $args. 這個變量在讀取時傳回目前請求的 URL 參數串(即請求 URL 中問号後面的部分,如果有的話 ),而在指派時可以直接修改參數串
例如:
location /test {
set $orig_args $args;
set $args "a=3&b=4";
echo "original args: $orig_args";
echo "args: $args";
}
通路和輸出:
$ 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
像 $arg_XXX 這樣具有無數變種的變量群,是“未索引的”。當讀取這樣的變量時,其實是它的“取處理程式”(get(xxx))在起作用,即實時掃描目前請求的 URL 參數串,提取出變量名所指定的 URL 參數的值。很多新手都會對 $arg_XXX的實作方式産生誤解,以為 Nginx 會事先解析好目前請求的所有 URL 參數,并且把相關的$arg_XXX變量的值都事先設定好。然而事實并非如此,Nginx 根本不會事先就解析好 URL 參數串,而是在使用者讀取某個$arg_XXX 變量時,調用其“取處理程式”,即時去掃描 URL 參數串。類似地,内建變量 $cookie_XXX 也是通過它的“取處理程式”,即時去掃描
Cookie
請求頭中的相關定義的。