一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

云服務(wù)器|WEB服務(wù)器|FTP服務(wù)器|郵件服務(wù)器|虛擬主機(jī)|服務(wù)器安全|DNS服務(wù)器|服務(wù)器知識(shí)|Nginx|IIS|Tomcat|

服務(wù)器之家 - 服務(wù)器技術(shù) - Nginx - 淺析Nginx配置文件中的變量的編寫使用

淺析Nginx配置文件中的變量的編寫使用

2019-11-06 12:10agentzh Nginx

這篇文章主要介紹了Nginx配置文件中的變量的編寫使用,包括從常用的rewrite等方面來深入變量的相關(guān)定義,需要的朋友可以參考下

nginx 的配置文件使用的就是一門微型的編程語言,許多真實(shí)世界里的 Nginx 配置文件其實(shí)就是一個(gè)一個(gè)的小程序。當(dāng)然,是不是“圖靈完全的”暫且不論,至少據(jù)我觀察,它在設(shè)計(jì)上受 Perl 和 Bourne shell 這兩種語言的影響很大。在這一點(diǎn)上,相比 Apache 和 Lighttpd 等其他 Web 服務(wù)器的配置記法,不能不說算是 Nginx 的一大特色了。既然是編程語言,一般也就少不了“變量”這種東西(當(dāng)然,Haskell 這樣奇怪的函數(shù)式語言除外了)。
熟悉 Perl、Bourne shell、C/C++ 等命令式編程語言的朋友肯定知道,變量說白了就是存放“值”的容器。而所謂“值”,在許多編程語言里,既可以是 3.14 這樣的數(shù)值,也可以是 hello world 這樣的字符串,甚至可以是像數(shù)組、哈希表這樣的復(fù)雜數(shù)據(jù)結(jié)構(gòu)。然而,在 Nginx 配置中,變量只能存放一種類型的值,因?yàn)橐仓淮嬖谝环N類型的值,那就是字符串。
比如我們的 nginx.conf 文件中有下面這一行配置:

?
1
set $a "hello world";

我們使用了標(biāo)準(zhǔn) ngx_rewrite 模塊的 set 配置指令對(duì)變量 $a 進(jìn)行了賦值操作。特別地,我們把字符串 hello world 賦給了它。
我們看到,Nginx 變量名前面有一個(gè) $ 符號(hào),這是記法上的要求。所有的 Nginx 變量在 Nginx 配置文件中引用時(shí)都須帶上 $ 前綴。這種表示方法和 Perl、PHP 這些語言是相似的。
雖然 $ 這樣的變量前綴修飾會(huì)讓正統(tǒng)的 Java 和 C# 程序員不舒服,但這種表示方法的好處也是顯而易見的,那就是可以直接把變量嵌入到字符串常量中以構(gòu)造出新的字符串:

?
1
2
set $a hello; 
set $b "$a, $a";

這里我們通過已有的 Nginx 變量 $a 的值,來構(gòu)造變量 $b 的值,于是這兩條指令順序執(zhí)行完之后,$a 的值是 hello,而 $b 的值則是 hello, hello. 這種技術(shù)在 Perl 世界里被稱為“變量插值”(variable interpolation),它讓專門的字符串拼接運(yùn)算符變得不再那么必要。我們?cè)谶@里也不妨采用此術(shù)語。
我們來看一個(gè)比較完整的配置示例:

?
1
2
3
4
5
6
7
8
server { 
  listen 8080; 
 
  location /test { 
    set $foo hello; 
    echo "foo: $foo"; 
  
}

 
這個(gè)例子省略了 nginx.conf 配置文件中最外圍的 http 配置塊以及 events 配置塊。使用 curl 這個(gè) HTTP 客戶端在命令行上請(qǐng)求這個(gè) /test 接口,我們可以得到

?
1
2
$ curl 'http://localhost:8080/test' 
foo: hello

這里我們使用第三方 ngx_echo 模塊的 echo 配置指令將 $foo 變量的值作為當(dāng)前請(qǐng)求的響應(yīng)體輸出。
我們看到,echo 配置指令的參數(shù)也支持“變量插值”。不過,需要說明的是,并非所有的配置指令都支持“變量插值”。事實(shí)上,指令參數(shù)是否允許“變量插值”,取決于該指令的實(shí)現(xiàn)模塊。
如果我們想通過 echo 指令直接輸出含有“美元符”($)的字符串,那么有沒有辦法把特殊的 $ 字符給轉(zhuǎn)義掉呢?答案是否定的(至少到目前最新的 Nginx 穩(wěn)定版 1.0.10)。不過幸運(yùn)的是,我們可以繞過這個(gè)限制,比如通過不支持“變量插值”的模塊配置指令專門構(gòu)造出取值為 $ 的 Nginx 變量,然后再在 echo 中使用這個(gè)變量。看下面這個(gè)例子:

?
1
2
3
4
5
6
7
8
9
10
11
geo $dollar { 
  default "$"; 
 
server { 
  listen 8080; 
 
  location /test { 
    echo "This is a dollar sign: $dollar"; 
  
}

測(cè)試結(jié)果如下:

?
1
2
$ curl 'http://localhost:8080/test' 
This is a dollar sign: $

這里用到了標(biāo)準(zhǔn)模塊 ngx_geo 提供的配置指令 geo 來為變量 $dollar 賦予字符串 "$",這樣我們?cè)谙旅嫘枰褂妹涝牡胤剑椭苯右梦覀兊?$dollar 變量就可以了。其實(shí) ngx_geo 模塊最常規(guī)的用法是根據(jù)客戶端的 IP 地址對(duì)指定的 Nginx 變量進(jìn)行賦值,這里只是借用它以便“無條件地”對(duì)我們的 $dollar 變量賦予“美元符”這個(gè)值。
在“變量插值”的上下文中,還有一種特殊情況,即當(dāng)引用的變量名之后緊跟著變量名的構(gòu)成字符時(shí)(比如后跟字母、數(shù)字以及下劃線),我們就需要使用特別的記法來消除歧義,例如:

?
1
2
3
4
5
6
7
8
server { 
  listen 8080; 
 
  location /test { 
    set $first "hello "; 
    echo "${first}world"; 
  
}

 
這里,我們?cè)?echo 配置指令的參數(shù)值中引用變量 $first 的時(shí)候,后面緊跟著 world 這個(gè)單詞,所以如果直接寫作 "$firstworld" 則 Nginx “變量插值”計(jì)算引擎會(huì)將之識(shí)別為引用了變量 $firstworld. 為了解決這個(gè)難題,Nginx 的字符串記法支持使用花括號(hào)在 $ 之后把變量名圍起來,比如這里的 ${first}. 上面這個(gè)例子的輸出是:

?
1
2
$ curl 'http://localhost:8080/test 
hello world

set 指令(以及前面提到的 geo 指令)不僅有賦值的功能,它還有創(chuàng)建 Nginx 變量的副作用,即當(dāng)作為賦值對(duì)象的變量尚不存在時(shí),它會(huì)自動(dòng)創(chuàng)建該變量。比如在上面這個(gè)例子中,如果 $a 這個(gè)變量尚未創(chuàng)建,則 set 指令會(huì)自動(dòng)創(chuàng)建 $a 這個(gè)用戶變量。如果我們不創(chuàng)建就直接使用它的值,則會(huì)報(bào)錯(cuò)。例如

?
1
2
3
4
5
6
7
server { 
 listen 8080; 
 
 location /bad { 
   echo $foo; 
 
}

此時(shí) Nginx 服務(wù)器會(huì)拒絕加載配置:

?
1
[emerg] unknown "foo" variable

是的,我們甚至都無法啟動(dòng)服務(wù)!
有趣的是,Nginx 變量的創(chuàng)建和賦值操作發(fā)生在全然不同的時(shí)間階段。Nginx 變量的創(chuàng)建只能發(fā)生在 Nginx 配置加載的時(shí)候,或者說 Nginx 啟動(dòng)的時(shí)候;而賦值操作則只會(huì)發(fā)生在請(qǐng)求實(shí)際處理的時(shí)候。這意味著不創(chuàng)建而直接使用變量會(huì)導(dǎo)致啟動(dòng)失敗,同時(shí)也意味著我們無法在請(qǐng)求處理時(shí)動(dòng)態(tài)地創(chuàng)建新的 Nginx 變量。
Nginx 變量一旦創(chuàng)建,其變量名的可見范圍就是整個(gè) Nginx 配置,甚至可以跨越不同虛擬主機(jī)的 server 配置塊。我們來看一個(gè)例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
server { 
  listen 8080; 
 
  location /foo { 
    echo "foo = [$foo]"; 
  
 
  location /bar { 
    set $foo 32; 
    echo "foo = [$foo]"; 
  
}

 
這里我們?cè)?location /bar 中用 set 指令創(chuàng)建了變量 $foo,于是在整個(gè)配置文件中這個(gè)變量都是可見的,因此我們可以在 location /foo 中直接引用這個(gè)變量而不用擔(dān)心 Nginx 會(huì)報(bào)錯(cuò)。
下面是在命令行上用 curl 工具訪問這兩個(gè)接口的結(jié)果:

?
1
2
3
4
5
6
$ curl 'http://localhost:8080/foo' 
foo = [] 
$ curl 'http://localhost:8080/bar' 
foo = [32] 
$ curl 'http://localhost:8080/foo' 
foo = []

從這個(gè)例子我們可以看到,set 指令因?yàn)槭窃?location /bar 中使用的,所以賦值操作只會(huì)在訪問 /bar 的請(qǐng)求中執(zhí)行。而請(qǐng)求 /foo 接口時(shí),我們總是得到空的 $foo 值,因?yàn)橛脩糇兞课促x值就輸出的話,得到的便是空字符串。
從這個(gè)例子我們可以窺見的另一個(gè)重要特性是,Nginx 變量名的可見范圍雖然是整個(gè)配置,但每個(gè)請(qǐng)求都有所有變量的獨(dú)立副本,或者說都有各變量用來存放值的容器的獨(dú)立副本,彼此互不干擾。比如前面我們請(qǐng)求了 /bar 接口后,$foo 變量被賦予了值 32,但它絲毫不會(huì)影響后續(xù)對(duì) /foo 接口的請(qǐng)求所對(duì)應(yīng)的 $foo 值(它仍然是空的!),因?yàn)楦鱾€(gè)請(qǐng)求都有自己獨(dú)立的 $foo 變量的副本。
對(duì)于 Nginx 新手來說,最常見的錯(cuò)誤之一,就是將 Nginx 變量理解成某種在請(qǐng)求之間全局共享的東西,或者說“全局變量”。而事實(shí)上,Nginx 變量的生命期是不可能跨越請(qǐng)求邊界的。

關(guān)于 nginx 變量的另一個(gè)常見誤區(qū)是認(rèn)為變量容器的生命期,是與 location 配置塊綁定的。其實(shí)不然。我們來看一個(gè)涉及“內(nèi)部跳轉(zhuǎn)”的例子:

?
1
2
3
4
5
6
7
8
9
10
server { 
  listen 8080; 
  location /foo { 
    set $a hello; 
    echo_exec /bar; 
  
  location /bar { 
    echo "a = [$a]"; 
  
}

這里我們?cè)?location /foo 中,使用第三方模塊 ngx_echo 提供的 echo_exec 配置指令,發(fā)起到 location /bar 的“內(nèi)部跳轉(zhuǎn)”。所謂“內(nèi)部跳轉(zhuǎn)”,就是在處理請(qǐng)求的過程中,于服務(wù)器內(nèi)部,從一個(gè) location 跳轉(zhuǎn)到另一個(gè) location 的過程。這不同于利用 HTTP 狀態(tài)碼 301 和 302 所進(jìn)行的“外部跳轉(zhuǎn)”,因?yàn)楹笳呤怯?HTTP 客戶端配合進(jìn)行跳轉(zhuǎn)的,而且在客戶端,用戶可以通過瀏覽器地址欄這樣的界面,看到請(qǐng)求的 URL 地址發(fā)生了變化。內(nèi)部跳轉(zhuǎn)和 Bourne shell(或 Bash)中的 exec 命令很像,都是“有去無回”。另一個(gè)相近的例子是 C 語言中的 goto 語句。
既然是內(nèi)部跳轉(zhuǎn),當(dāng)前正在處理的請(qǐng)求就還是原來那個(gè),只是當(dāng)前的 location 發(fā)生了變化,所以還是原來的那一套 nginx 變量的容器副本。對(duì)應(yīng)到上例,如果我們請(qǐng)求的是 /foo 這個(gè)接口,那么整個(gè)工作流程是這樣的:先在 location /foo 中通過 set 指令將 $a 變量的值賦為字符串 hello,然后通過 echo_exec 指令發(fā)起內(nèi)部跳轉(zhuǎn),又進(jìn)入到 location /bar 中,再輸出 $a 變量的值。因?yàn)?$a 還是原來的 $a,所以我們可以期望得到 hello 這行輸出。測(cè)試證實(shí)了這一點(diǎn):

?
1
2
$ curl localhost:8080/foo 
a = [hello]

但如果我們從客戶端直接訪問 /bar 接口,就會(huì)得到空的 $a 變量的值,因?yàn)樗蕾囉?location /foo 來對(duì) $a 進(jìn)行初始化。從上面這個(gè)例子我們看到,一個(gè)請(qǐng)求在其處理過程中,即使經(jīng)歷多個(gè)不同的 location 配置塊,它使用的還是同一套 Nginx 變量的副本。這里,我們也首次涉及到了“內(nèi)部跳轉(zhuǎn)”這個(gè)概念。值得一提的是,標(biāo)準(zhǔn) ngx_rewrite 模塊的 rewrite 配置指令其實(shí)也可以發(fā)起“內(nèi)部跳轉(zhuǎn)”,例如上面那個(gè)例子用 rewrite 配置指令可以改寫成下面這樣的形式:

?
1
2
3
4
5
6
7
8
9
10
server { 
  listen 8080; 
  location /foo { 
    set $a hello; 
    rewrite ^ /bar; 
  
  location /bar { 
    echo "a = [$a]"; 
  
}

 
其效果和使用 echo_exec 是完全相同的。后面我們還會(huì)專門介紹這個(gè) rewrite 指令的更多用法,比如發(fā)起 301 和 302 這樣的“外部跳轉(zhuǎn)”。從上面這個(gè)例子我們看到,Nginx 變量值容器的生命期是與當(dāng)前正在處理的請(qǐng)求綁定的,而與 location 無關(guān)。前面我們接觸到的都是通過 set 指令隱式創(chuàng)建的 Nginx 變量。這些變量我們一般稱為“用戶自定義變量”,或者更簡單一些,“用戶變量”。既然有“用戶自定義變量”,自然也就有由 Nginx 核心和各個(gè) Nginx 模塊提供的“預(yù)定義變量”,或者說“內(nèi)建變量”(builtin variables)。Nginx 內(nèi)建變量最常見的用途就是獲取關(guān)于請(qǐng)求或響應(yīng)的各種信息。例如由 ngx_http_core 模塊提供的內(nèi)建變量 $uri,可以用來獲取當(dāng)前請(qǐng)求的 URI(經(jīng)過解碼,并且不含請(qǐng)求參數(shù)),而 $request_uri 則用來獲取請(qǐng)求最原始的 URI (未經(jīng)解碼,并且包含請(qǐng)求參數(shù))。請(qǐng)看下面這個(gè)例子:

?
1
2
3
4
location /test { 
  echo "uri = $uri"; 
  echo "request_uri = $request_uri"; 
}

這里為了簡單起見,連 server 配置塊也省略了,和前面所有示例一樣,我們監(jiān)聽的依然是 8080 端口。在這個(gè)例子里,我們把 $uri 和 $request_uri 的值輸出到響應(yīng)體中去。下面我們用不同的請(qǐng)求來測(cè)試一下這個(gè) /test 接口:

?
1
2
3
4
5
6
7
8
9
$ 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

另一個(gè)特別常用的內(nèi)建變量其實(shí)并不是單獨(dú)一個(gè)變量,而是有無限多變種的一群變量,即名字以 arg_ 開頭的所有變量,我們估且稱之為 $arg_XXX 變量群。一個(gè)例子是 $arg_name,這個(gè)變量的值是當(dāng)前請(qǐng)求名為 name 的 URI 參數(shù)的值,而且還是未解碼的原始形式的值。我們來看一個(gè)比較完整的示例:

?
1
2
3
4
location /test { 
  echo "name: $arg_name"; 
  echo "class: $arg_class"; 
}

 
然后在命令行上使用各種參數(shù)組合去請(qǐng)求這個(gè) /test 接口:

?
1
2
3
4
5
6
7
8
9
$ 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

其實(shí) $arg_name 不僅可以匹配 name 參數(shù),也可以匹配 NAME 參數(shù),抑或是 Name,等等:

?
1
2
3
4
5
6
$ curl 'http://localhost:8080/test?NAME=Marry' 
name: Marry 
class: 
$ curl 'http://localhost:8080/test?Name=Jimmy' 
name: Jimmy 
class:

Nginx 會(huì)在匹配參數(shù)名之前,自動(dòng)把原始請(qǐng)求中的參數(shù)名調(diào)整為全部小寫的形式。
如果你想對(duì) URI 參數(shù)值中的 %XX 這樣的編碼序列進(jìn)行解碼,可以使用第三方 ngx_set_misc 模塊提供的 set_unescape_uri 配置指令:

?
1
2
3
4
5
6
location /test { 
  set_unescape_uri $name $arg_name; 
  set_unescape_uri $class $arg_class; 
  echo "name: $name"; 
  echo "class: $class"; 
}

現(xiàn)在我們?cè)倏匆幌滦Ч?/p>

?
1
2
3
$ curl 'http://localhost:8080/test?name=hello%20world&class=9' 
name: hello world 
class: 9

 
空格果然被解碼出來了!
從這個(gè)例子我們同時(shí)可以看到,這個(gè) set_unescape_uri 指令也像 set 指令那樣,擁有自動(dòng)創(chuàng)建 Nginx 變量的功能。后面我們還會(huì)專門介紹到 ngx_set_misc 模塊。像 $arg_XXX 這種類型的變量擁有無窮無盡種可能的名字,所以它們并不對(duì)應(yīng)任何存放值的容器。而且這種變量在 Nginx 核心中是經(jīng)過特別處理的,第三方 Nginx 模塊是不能提供這樣充滿魔法的內(nèi)建變量的。類似 $arg_XXX 的內(nèi)建變量還有不少,比如用來取 cookie 值的 $cookie_XXX 變量群,用來取請(qǐng)求頭的 $http_XXX 變量群,以及用來取響應(yīng)頭的 $sent_http_XXX 變量群。這里就不一一介紹了,感興趣的讀者可以參考 ngx_http_core 模塊的官方文檔。需要指出的是,許多內(nèi)建變量都是只讀的,比如我們剛才介紹的 $uri 和 $request_uri. 對(duì)只讀變量進(jìn)行賦值是應(yīng)當(dāng)絕對(duì)避免的,因?yàn)闀?huì)有意想不到的后果,比如:

?
1
2
3
4
location /bad { 
 set $uri /blah; 
 echo $uri; 
}

這個(gè)有問題的配置會(huì)讓 Nginx 在啟動(dòng)的時(shí)候報(bào)出一條令人匪夷所思的錯(cuò)誤:

?
1
[emerg] the duplicate "uri" variable in ...

如果你嘗試改寫另外一些只讀的內(nèi)建變量,比如 $arg_XXX 變量,在某些 Nginx 的版本中甚至可能導(dǎo)致進(jìn)程崩潰。
也有一些內(nèi)建變量是支持改寫的,其中一個(gè)例子是 $args. 這個(gè)變量在讀取時(shí)返回當(dāng)前請(qǐng)求的 URL 參數(shù)串(即請(qǐng)求 URL 中問號(hào)后面的部分,如果有的話 ),而在賦值時(shí)可以直接修改參數(shù)串。我們來看一個(gè)例子:

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

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

?
1
2
3
4
5
6
$ 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

 
在第一次測(cè)試中,我們沒有設(shè)置任何 URL 參數(shù)串,所以輸出 $orig_args 變量的值時(shí)便得到空。而在第一次和第二次測(cè)試中,無論我們是否提供 URL 參數(shù)串,參數(shù)串都會(huì)在 location /test 中被強(qiáng)行改寫成 a=3&b=4.
需要特別指出的是,這里的 $args 變量和 $arg_XXX 一樣,也不再使用屬于自己的存放值的容器。當(dāng)我們讀取 $args 時(shí),nginx 會(huì)執(zhí)行一小段代碼,從 Nginx 核心中專門存放當(dāng)前 URL 參數(shù)串的位置去讀取數(shù)據(jù);而當(dāng)我們改寫 $args 時(shí),Nginx 會(huì)執(zhí)行另一小段代碼,對(duì)相同位置進(jìn)行改寫。Nginx 的其他部分在需要當(dāng)前 URL 參數(shù)串的時(shí)候,都會(huì)從那個(gè)位置去讀數(shù)據(jù),所以我們對(duì) $args 的修改會(huì)影響到所有部分的功能。我們來看一個(gè)例子:

?
1
2
3
4
5
6
location /test { 
  set $orig_a $arg_a; 
  set $args "a=5"; 
  echo "original a: $orig_a"; 
  echo "a: $arg_a"; 
}

這里我們先把內(nèi)建變量 $arg_a 的值,即原始請(qǐng)求的 URL 參數(shù) a 的值,保存在用戶變量 $orig_a 中,然后通過對(duì)內(nèi)建變量 $args 進(jìn)行賦值,把當(dāng)前請(qǐng)求的參數(shù)串改寫為 a=5 ,最后再用 echo 指令分別輸出 $orig_a 和 $arg_a 變量的值。因?yàn)閷?duì)內(nèi)建變量 $args 的修改會(huì)直接導(dǎo)致當(dāng)前請(qǐng)求的 URL 參數(shù)串發(fā)生變化,因此內(nèi)建變量 $arg_XXX 自然也會(huì)隨之變化。測(cè)試的結(jié)果證實(shí)了這一點(diǎn):

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

我們看到,因?yàn)樵颊?qǐng)求的 URL 參數(shù)串是 a=3, 所以 $arg_a 最初的值為 3, 但隨后通過改寫 $args 變量,將 URL 參數(shù)串又強(qiáng)行修改為 a=5, 所以最終 $arg_a 的值又自動(dòng)變?yōu)榱?5.我們?cè)賮砜匆粋€(gè)通過修改 $args 變量影響標(biāo)準(zhǔn)的 HTTP 代理模塊 ngx_proxy 的例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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"; 
  
}

 
這里我們?cè)?http 配置塊中定義了兩個(gè)虛擬主機(jī)。第一個(gè)虛擬主機(jī)監(jiān)聽 8080 端口,其 /test 接口自己通過改寫 $args 變量,將當(dāng)前請(qǐng)求的 URL 參數(shù)串無條件地修改為 foo=1&bar=2. 然后 /test 接口再通過 ngx_proxy 模塊的 proxy_pass 指令配置了一個(gè)反向代理,指向本機(jī)的 8081 端口上的 HTTP 服務(wù) /args. 默認(rèn)情況下,ngx_proxy 模塊在轉(zhuǎn)發(fā) HTTP 請(qǐng)求到遠(yuǎn)方 HTTP 服務(wù)的時(shí)候,會(huì)自動(dòng)把當(dāng)前請(qǐng)求的 URL 參數(shù)串也轉(zhuǎn)發(fā)到遠(yuǎn)方。而本機(jī)的 8081 端口上的 HTTP 服務(wù)正是由我們定義的第二個(gè)虛擬主機(jī)來提供的。我們?cè)诘诙€(gè)虛擬主機(jī)的 location /args 中利用 echo 指令輸出當(dāng)前請(qǐng)求的 URL 參數(shù)串,以檢查 /test 接口通過 ngx_proxy 模塊實(shí)際轉(zhuǎn)發(fā)過來的 URL 請(qǐng)求參數(shù)串。我們來實(shí)際訪問一下第一個(gè)虛擬主機(jī)的 /test 接口:

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

我們看到,雖然請(qǐng)求自己提供了 URL 參數(shù)串 blah=7,但在 location /test 中,參數(shù)串被強(qiáng)行改寫成了 foo=1&bar=2. 接著經(jīng)由 proxy_pass 指令將我們被改寫掉的參數(shù)串轉(zhuǎn)發(fā)給了第二個(gè)虛擬主機(jī)上配置的 /args 接口,然后再把 /args 接口的 URL 參數(shù)串輸出。事實(shí)證明,我們對(duì) $args 變量的賦值操作,也成功影響到了 ngx_proxy 模塊的行為。
在讀取變量時(shí)執(zhí)行的這段特殊代碼,在 Nginx 中被稱為“取處理程序”(get handler);而改寫變量時(shí)執(zhí)行的這段特殊代碼,則被稱為“存處理程序”(set handler)。不同的 Nginx 模塊一般會(huì)為它們的變量準(zhǔn)備不同的“存取處理程序”,從而讓這些變量的行為充滿魔法。其實(shí)這種技巧在計(jì)算世界并不鮮見。比如在面向?qū)ο缶幊讨校惖脑O(shè)計(jì)者一般不會(huì)把類的成員變量直接暴露給類的用戶,而是另行提供兩個(gè)方法(method),分別用于該成員變量的讀操作和寫操作,這兩個(gè)方法常常被稱為“存取器”(accessor)。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 4455在线| 91tv破解版不限次数 | 成人在线观看视频免费 | 99资源在线观看 | 视频高清在线观看 | 九九精品免视频国产成人 | 韩国美女vip内部2020 | 五月天色小说 | wankz视频| 日韩精品在线视频观看 | 国产精品麻豆久久99 | 九九九国产在线 | 久久艹综合 | 微福利92合集 | 国产拍拍视频一二三四区 | 国产亚洲一级精品久久 | hd性欧美俱乐部中文 | 美女张开双腿让男人捅 | 日本高清中文字幕一区二区三区 | 国产性片在线观看 | 干妞网免费视频 | 国产精品免费_区二区三区观看 | 亚洲第一色区 | 扒开尿口| 18亚洲chinese男男1069 | 亚洲成在人网站天堂一区二区 | 俺去俺来也在线www色官网 | 王小军怎么了最新消息 | 王雨纯 羞羞 | 成人久久18免费网站 | 五月一区二区久久综合天堂 | 白丝vk丨tk失禁 | 欧美成人免费观看的 | 69罗莉视频在线观看 | 国产我不卡| 热99在线视频 | 国产在线视频一区二区三区 | 欧美日韩国产一区二区三区欧 | 情缘1完整版在线观看 | 青青草在线观看 | 91精品国产亚一区二区三区 |