Nginx
作為一個成熟、久經(jīng)考驗的負載均衡軟件,與其提供豐富、完整的內(nèi)置變量是分不開的,它極大增加了對Nginx
網(wǎng)絡(luò)行為的控制細度。這些變量大部分都是在請求進入時解析的,并把他們緩存到請求cycle
中,方便下一次獲取使用。首先來看看Nginx
對都開放了那些API
。
參看下表:
名稱 | 說明 |
---|---|
$arg_name | 請求中的name參數(shù) |
$args | 請求中的參數(shù) |
$binary_remote_addr | 遠程地址的二進制表示 |
$body_bytes_sent | 已發(fā)送的消息體字節(jié)數(shù) |
$content_length | HTTP請求信息里的"Content-Length" |
$content_type | 請求信息里的"Content-Type" |
$document_root | 針對當前請求的根路徑設(shè)置值 |
$document_uri | 與$uri相同; 比如 /test2/test.php |
$host | 請求信息中的"Host",如果請求中沒有Host行,則等于設(shè)置的服務(wù)器名 |
$hostname | 機器名使用 gethostname系統(tǒng)調(diào)用的值 |
$http_cookie | cookie 信息 |
$http_referer | 引用地址 |
$http_user_agent | 客戶端代理信息 |
$http_via | 最后一個訪問服務(wù)器的Ip地址。 |
$http_x_forwarded_for | 相當于網(wǎng)絡(luò)訪問路徑 |
$is_args | 如果請求行帶有參數(shù),返回“?”,否則返回空字符串 |
$limit_rate | 對連接速率的限制 |
$nginx_version | 當前運行的nginx版本號 |
$pid | worker進程的PID |
$query_string | 與$args相同 |
$realpath_root | 按root指令或alias指令算出的當前請求的絕對路徑。其中的符號鏈接都會解析成真是文件路徑 |
$remote_addr | 客戶端IP地址 |
$remote_port | 客戶端端口號 |
$remote_user | 客戶端用戶名,認證用 |
$request | 用戶請求 |
$request_body | 這個變量(0.7.58+)包含請求的主要信息。在使用proxy_pass或fastcgi_pass指令的location中比較有意義 |
$request_body_file | 客戶端請求主體信息的臨時文件名 |
$request_completion | 如果請求成功,設(shè)為"OK";如果請求未完成或者不是一系列請求中最后一部分則設(shè)為空 |
$request_filename | 當前請求的文件路徑名,比如/opt/nginx/www/test.php |
$request_method | 請求的方法,比如"GET"、"POST"等 |
$request_uri | 請求的URI,帶參數(shù) |
$scheme | 所用的協(xié)議,比如http或者是https |
$server_addr | 服務(wù)器地址,如果沒有用listen指明服務(wù)器地址,使用這個變量將發(fā)起一次系統(tǒng)調(diào)用以取得地址(造成資源浪費) |
$server_name | 請求到達的服務(wù)器名 |
$server_port | 請求到達的服務(wù)器端口號 |
$server_protocol | 請求的協(xié)議版本,"HTTP/1.0"或"HTTP/1.1" |
$uri | 請求的URI,可能和最初的值有不同,比如經(jīng)過重定向之類的 |
其實這還不是全部,Nginx
在不停迭代更新是一個原因,還有一個是有些變量太冷門,借助它們,會有很多玩法。
首先,在OpenResty
中如何引用這些變量呢?參考 ngx.var.VARIABLE 小節(jié)。
利用這些內(nèi)置變量,來做一個簡單的數(shù)學(xué)求和運算例子:
server {
listen 80;
server_name localhost;
location /sum {
#處理業(yè)務(wù)
content_by_lua_block {
local a = tonumber(ngx.var.arg_a) or 0
local b = tonumber(ngx.var.arg_b) or 0
ngx.say("sum: ", a + b )
}
}
}
驗證一下:
? ~ curl 'http://127.0.0.1/sum?a=11&b=12'
sum: 23
也許你笑了,這個API
太簡單沒有實際意義。我們做個簡易防火墻,看看如何開始玩耍。
參看下面示例代碼:
server {
listen 80;
server_name localhost;
location /sum {
# 使用access階段完成準入階段處理
access_by_lua_block {
local black_ips = {["127.0.0.1"]=true}
local ip = ngx.var.remote_addr
if true == black_ips[ip] then
ngx.exit(ngx.HTTP_FORBIDDEN)
end
};
#處理業(yè)務(wù)
content_by_lua_block {
local a = tonumber(ngx.var.arg_a) or 0
local b = tonumber(ngx.var.arg_b) or 0
ngx.say("sum:", a + b )
}
}
}
運行測試:
? ~ curl '192.168.1.104/sum?a=11&b=12'
sum:23
? ~
? ~
? ~ curl '127.0.0.1/sum?a=11&b=12'
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>openresty/1.9.3.1</center>
</body>
</html>
通過測試結(jié)果看到,提取了終端的IP
地址后進行限制。擴充一下,就可以支持 IP 地址段,如果再與系統(tǒng)iptables
進行配合,那么就足以達到軟防火墻的目的。
目前為止,所有的例子都是對Nginx
內(nèi)置變量的獲取,是否可以對其進行設(shè)置呢?其實大多數(shù)內(nèi)容都是不允許寫入的,例如剛剛的終端IP
地址,在請求中是不允許對其進行更新的。對于可寫的變量中的limit_rate
,值得一提,它能完成傳輸速率限制,并且它的影響是單個請求級別。
參看下面示例:
location /download {
access_by_lua_block {
ngx.var.limit_rate = 1000
};
}
下載測試:
? ~ wget '127.0.0.1/download/1.cab'
--2015-09-13 13:59:51-- http://127.0.0.1/download/1.cab
Connecting to 127.0.0.1... connected.
HTTP request sent, awaiting response... 200 OK
Length: 135802 (133K) [application/octet-stream]
Saving to: '1.cab'
1.cab 6%[===> ] 8.00K 1.01KB/s eta 1m 53s