nginx 變量
Nginx 同 Apache 等其他 Web 服務(wù)器的配置記法不太相同排苍,Nginx的配置文件使用語法的就是一門微型的編程語言层释。可以類似寫程序一般編寫配置文件桨昙,可操作性很大扎拣。既然是編程語言,一般也就少不了“變量”這種東西稽鞭。
1鸟整、nginx變量簡介
所有的 Nginx變量在 Nginx 配置文件中引用時都須帶上 $ 前綴
在 Nginx 配置中,變量只能存放一種類型的值朦蕴,有且也只存在一種類型篮条,那就是字符串類型
nginx可以使用變量簡化配置與提高配置的靈活性,所有的變量值都可以通過這種方式引用:
$變量名
2梦重、nginx 變量的定義和使用
nginx中的變量分為兩種兑燥,自定義變量與內(nèi)置預(yù)定義變量
1、自定義變量
1琴拧、聲明變量可以在sever,http,location等標(biāo)簽中使用set命令(非唯一)聲明變量,語法如下
set$變量名 變量值
注意:
nginx 中的變量必須都以$開頭
nginx 的配置文件中所有使用的變量都必須是聲明過的嘱支,否則 nginx 會無法啟動并打印相關(guān)異常日志
2蚓胸、變量的可見性
在不同層級的標(biāo)簽中聲明的變量性的可見性規(guī)則如下:
location標(biāo)簽中聲明的變量中對這個location塊可見
server標(biāo)簽中聲明的變量對server塊以及server塊中的所有子塊可見
http標(biāo)簽中聲明的變量對http塊以及http塊中的所有子塊可見
nginx安裝echo模塊
查看已經(jīng)安裝的nginx的版本
[root@192 ~]# nginx -V
下載echo模塊的安裝包
[root@192 ~]# wget https://github.com/openresty/echo-nginx-module/archive/v0.61.tar.gz
[root@192 ~]# ls
anaconda-ks.cfg? nginx-1.16.0.tar.gz? v0.61.tar.gz
解壓到相同路徑下:
[root@192 ~]# tar xzf nginx-1.16.0.tar.gz -C /usr/local/
[root@192 ~]# tar xzf v0.61.tar.gz -C /usr/local/
安裝編譯工具
[root@192 ~]# cd /usr/local/
[root@192 local]# yum -y install pcre pcre-devel openssl openssl-devel gcc gcc-c++ ? zlib zlib-devel
添加模塊:
[root@192 local]# cd nginx-1.16.0/
添加上原來已經(jīng)有的參數(shù)和新添加的模塊:
[root@192 nginx-1.16.0]# ./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' --add-module=/usr/local/echo-nginx-module-0.61
[root@192 nginx-1.16.0]# make ? #編譯,不要make install 否則會覆蓋原來的文件
[root@192 nginx-1.16.0]#? mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx_bak2 #將原來的nignx備份
[root@192 nginx-1.16.0]# cp objs/nginx /usr/local/nginx/sbin/? 拷貝nignx
[root@192 nginx-1.16.0]# /usr/local/nginx/sbin/nginx? #啟動
[root@192 nginx-1.16.0]# nginx -V? 查看模塊是否添加成功
nginx version: nginx/1.16.0
built bygcc4.8.520150623(Red Hat4.8.5-36) (GCC)
built with OpenSSL1.0.2k-fips26Jan2017
TLS SNI support enabled
configure arguments:--prefix=/etc/nginx--sbin-path=/usr/sbin/nginx--modules-path=/usr/lib64/nginx/modules--conf-path=/etc/nginx/nginx.conf--error-log-path=/var/log/nginx/error.log--http-log-path=/var/log/nginx/access.log--pid-path=/var/run/nginx.pid--lock-path=/var/run/nginx.lock--http-client-body-temp-path=/var/cache/nginx/client_temp--http-proxy-temp-path=/var/cache/nginx/proxy_temp--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp--http-scgi-temp-path=/var/cache/nginx/scgi_temp--user=nginx--group=nginx--with-compat--with-file-aio--with-threads--with-http_addition_module--with-http_auth_request_module--with-http_dav_module--with-http_flv_module--with-http_gunzip_module--with-http_gzip_static_module--with-http_mp4_module--with-http_random_index_module--with-http_realip_module--with-http_secure_link_module--with-http_slice_module--with-http_ssl_module--with-http_stub_status_module--with-http_sub_module--with-http_v2_module--with-mail--with-mail_ssl_module--with-stream--with-stream_realip_module--with-stream_ssl_module--with-stream_ssl_preread_module--with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC'--with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'--add-module=/usr/local/echo-nginx-module-0.61
3除师、配置 $foo=hello
[root@192 ~]# cd /etc/nginx/conf.d/
[root@192 conf.d]# vim echo.conf
server {
listen80;
? ? ?? server_name ? ? localhost;
? ? ?? location /test {
set$foohello;
echo"foo: $foo";
? ? ?? }
}
輸出
[root@192 conf.d]# nginx -s reload
[root@192 conf.d]# curl localhost/test
foo: hello
5沛膳、 使用大括號插值
在“變量插值”的上下文中,還有一種特殊情況汛聚,即當(dāng)引用的變量名之后緊跟著變量名的構(gòu)成字符時(比如后跟字母锹安、數(shù)字以及下劃線),我們就需要使用特別的記法來消除歧義倚舀,例如:
server {
listen80;
? ? ?? server_name ? ? localhost;
? ? ?? location /test-brace {
set$first"hello ";
echo"${first}world";
? ? ?? }
}
輸出
[root@192 conf.d]# nginx -s reload
[root@192 conf.d]# curl localhost/test-brace
hello world
這里叹哭,我們在 echo 配置指令的參數(shù)值中引用變量 first 的時候,后面緊跟著 world 這個單詞痕貌,所以如果直接寫作 "firstworld" 則 Nginx “變量插值”計算引擎會將之識別為引用了變量 firstworld. 為了解決這個難題风罩,Nginx 的字符串記法支持使用花括號在? 之后把變量名圍起來,比如這里的 ${first}舵稠。
6超升、變量作用域
set 指令不僅有賦值的功能入宦,它還有創(chuàng)建 Nginx 變量的副作用,即當(dāng)作為賦值對象的變量尚不存在時室琢,它會自動創(chuàng)建該變量乾闰。比如在上面這個例子中,如果 $a 這個變量尚未創(chuàng)建盈滴,則 set 指令會自動創(chuàng)建 $a 這個用戶變量涯肩。如果我們不創(chuàng)建就直接使用它的值,則會報錯雹熬。 例如
server {
?? ...
?? location /bad {
echo$foo;
?? }
}
此時 Nginx 服務(wù)器會拒絕加載配置:
[root@192 conf.d]# nginx -s reload
nginx: [emerg] unknown"foo"variable
nginx: configuration file /etc/nginx/nginx.conf test failed
Nginx 變量的創(chuàng)建和賦值操作發(fā)生在全然不同的時間階段宽菜,Nginx 變量的創(chuàng)建只能發(fā)生在 Nginx 配置加載的時候,或者說 Nginx 啟動的時候竿报,而賦值操作則只會發(fā)生在請求實際處理的時候铅乡。 這意味著不創(chuàng)建而直接使用變量會導(dǎo)致啟動失敗,同時也意味著我們無法在請求處理時動態(tài)地創(chuàng)建新的 Nginx 變量烈菌。
Nginx 變量一旦創(chuàng)建阵幸,其變量名的可見范圍就是整個 Nginx 配置,甚至可以跨越不同虛擬主機(jī)的 server 配置塊芽世。我們來看一個例子:
server {
listen80;
? ? ?? server_name ? ? localhost;
? ? ?? location /foo {
echo"foo = [$foo]";
? ? ?? }
? ? ?? location /bar {
set$foo32;
echo"foo = [$foo]";
? ? ?? }
}
輸出
[root@192 conf.d]# curl 'http://localhost/foo'
foo=[]
[root@192 conf.d]# curl 'http://localhost/bar'
foo=[32]
這里我們在 location /bar 中用 set 指令創(chuàng)建了變量 foo挚赊,于是在整個配置文件中這個變量都是可見的,因此我們可以在 location /foo 中直接引用這個變量而不用擔(dān)心 Nginx 會報錯济瓢。 從這個例子我們可以看到荠割,set 指令因為是在 location /bar 中使用的,所以賦值操作只會在訪問 /bar 的請求中執(zhí)行旺矾。而請求 /foo 接口時蔑鹦,我們總是得到空的 foo值,因為用戶變量未賦值就輸出的話箕宙,得到的便是空字符串嚎朽。
從這個例子我們可以窺見的另一個重要特性是,Nginx 變量名的可見范圍雖然是整個配置柬帕,但每個請求都有所有變量的獨立副本哟忍,或者說都有各變量用來存放值的容器的獨立副本,彼此互不干擾陷寝。比如前面我們請求了 /bar 接口后锅很,foo 變量被賦予了值 32,但它絲毫不會影響后續(xù)對 /foo 接口的請求所對應(yīng)的 foo 值(它仍然是空的E翁)粗蔚,因為各個請求都有自己獨立的 $foo 變量的副本。
2饶火、內(nèi)置預(yù)定義變量
內(nèi)置預(yù)定義變量即無需聲明就可以使用的變量鹏控,通常包括一個http請求或響應(yīng)中一部分內(nèi)容的值致扯,以下為一些常用的內(nèi)置預(yù)定義變量
變量名定義
$arg_PARAMETERGET請求中變量名PARAMETER參數(shù)的值。
$args這個變量等于GET請求中的參數(shù)当辐。例如抖僵,foo=123&bar=blahblah;這個變量只可以被修改
$binary_remote_addr二進(jìn)制碼形式的客戶端地址。
$body_bytes_sent傳送頁面的字節(jié)數(shù)
$content_length請求頭中的Content-length字段缘揪。
$content_type請求頭中的Content-Type字段耍群。
$cookie_COOKIEcookie COOKIE的值。
$document_root當(dāng)前請求在root指令中指定的值。
$document_uri與$uri相同。
$host請求中的主機(jī)頭(Host)字段丈咐,如果請求中的主機(jī)頭不可用或者空,則為處理請求的server名稱(處理請求的server的server_name指令的值)曹抬。值為小寫,不包含端口急鳄。
$hostname機(jī)器名使用 gethostname系統(tǒng)調(diào)用的值
$http_HEADERHTTP請求頭中的內(nèi)容谤民,HEADER為HTTP請求中的內(nèi)容轉(zhuǎn)為小寫,-變?yōu)開(破折號變?yōu)橄聞澗€)疾宏,例如:$http_user_agent(Uaer-Agent的值);
$sent_http_HEADERHTTP響應(yīng)頭中的內(nèi)容张足,HEADER為HTTP響應(yīng)中的內(nèi)容轉(zhuǎn)為小寫,-變?yōu)開(破折號變?yōu)橄聞澗€)坎藐,例如: $sent_http_cache_control, $sent_http_content_type…;
$is_args如果$args設(shè)置为牍,值為"?",否則為""岩馍。
$limit_rate這個變量可以限制連接速率吵聪。
$nginx_version當(dāng)前運行的nginx版本號。
$query_string與$args相同兼雄。
$remote_addr客戶端的IP地址。
$remote_port客戶端的端口帽蝶。
$remote_user已經(jīng)經(jīng)過Auth Basic Module驗證的用戶名赦肋。
$request_filename當(dāng)前連接請求的文件路徑,由root或alias指令與URI請求生成励稳。
$request_body這個變量(0.7.58+)包含請求的主要信息佃乘。在使用proxy_pass或fastcgi_pass指令的location中比較有意義。
$request_body_file客戶端請求主體信息的臨時文件名驹尼。
$request_completion如果請求成功趣避,設(shè)為"OK";如果請求未完成或者不是一系列請求中最后一部分則設(shè)為空新翎。
$request_method這個變量是客戶端請求的動作程帕,通常為GET或POST住练。包括0.8.20及之前的版本中,這個變量總為main request中的動作愁拭,如果當(dāng)前請求是一個子請求讲逛,并不使用這個當(dāng)前請求的動作。
$request_uri這個變量等于包含一些客戶端請求參數(shù)的原始URI岭埠,它無法修改盏混,請查看$uri更改或重寫URI。
$scheme所用的協(xié)議惜论,比如http或者是https许赃,比如rewrite ^(.+)$ $scheme://example.com$1 redirect;
$server_addr服務(wù)器地址,在完成一次系統(tǒng)調(diào)用后可以確定這個值馆类,如果要繞開系統(tǒng)調(diào)用混聊,則必須在listen中指定地址并且使用bind參數(shù)。
$server_name服務(wù)器名稱蹦掐。
$server_port請求到達(dá)服務(wù)器的端口號技羔。
$server_protocol請求使用的協(xié)議,通常是HTTP/1.0或HTTP/1.1卧抗。
$uri請求中的當(dāng)前URI(不帶請求參數(shù)藤滥,參數(shù)位于args,不同于瀏覽器傳遞的args)社裆,不同于瀏覽器傳遞的request_uri的值拙绊,它可以通過內(nèi)部重定向,或者使用index指令進(jìn)行修改泳秀。不包括協(xié)議和主機(jī)名标沪,例如/foo/bar.html
Nginx 內(nèi)置變量最常見的用途就是獲取關(guān)于請求或響應(yīng)的各種信息。
1嗜傅、uri? vs request_uri
由 ngx_http_core 模塊提供的內(nèi)建變量 uri金句,可以用來獲取當(dāng)前請求的 URI(不含請求參數(shù)),而 request_uri 則用來獲取請求最原始的 URI(包含請求參數(shù))吕嘀。
server {
? ? ?? listen 80;
? ? ?? server_name ? ? localhost;
? ? ?? location /test-uri {
? ? ? ? ? ? ?? echo "uri = $uri";
? ? ? ? ? ? ?? echo "request_uri = $request_uri";
? ? ?? }
}
輸出
[root@localhost html]# nginx -s reload
[root@192 conf.d]# nginx -s reload
[root@192 conf.d]# curl localhost/test-uri
uri=/test-uri
request_uri=/test-uri
[root@192 conf.d]# curl "localhost/test-uri?a=3&b=4"
uri=/test-uri
request_uri=/test-uri?a=3&b=4
[root@192 conf.d]# curl "localhost/test-uri/hello%20world?a=3&b=4"
uri=/test-uri/hello world
request_uri=/test-uri/hello%20world?a=3&b=4
2违寞、$arg_XXX
另一個特別常用的內(nèi)建變量其實并不是單獨一個變量,而是有無限多變種的一群變量偶房,即名字以 arg_ 開頭的所有變量趁曼,我們估且稱之為 arg_XXX 變量群。 一個例子是 arg_name棕洋,這個變量的值是當(dāng)前請求中名為 name 的參數(shù)的值挡闰,而且還是未解碼的原始形式的值。
server {
listen80;
? ? ?? server_name ? ? localhost;
? ? ?? location /test-arg {
echo"name: $arg_name";
echo"class: $arg_class";
? ? ?? }
}
輸出
[root@192 conf.d]# nginx -s reload
[root@192 conf.d]# curl localhost/test-arg
name:
class:
?
[root@192 conf.d]# curl "localhost/test-arg?name=Tom&class=3"
name: Tom
class:3
?
[root@192 conf.d]# curl "localhost/test-arg?name=hello%20world&class=9"
name: hello%20world
class:9
3、$arg_XXX 不區(qū)分大小寫
其實 $arg_name 不僅可以匹配 name 參數(shù)摄悯,也可以匹配 NAME 參數(shù)赞季,抑或是 Name,Nginx 會在匹配參數(shù)名之前射众,自動把原始請求中的參數(shù)名調(diào)整為全部小寫的形式碟摆。
[root@192 conf.d]# curl "localhost/test-arg?NAME=Marry"
name: Marry
class:
[root@192 conf.d]# curl "localhost/test-arg?Name=Jimmy&class=DSfef"
name: Jimmy
class: DSfef