# 獲取Nginx內置綁定變量
`Nginx`作為一個成熟、久經考驗的負載均衡軟件,與其提供豐富、完整的內置變量是分不開的,它極大增加了我們對`Nginx`網絡行為的控制細度。這些變量大部分都是在請求進入時解析的,并把他們緩存到會話`cycle`中,方便下一次獲取使用。首先我們來看看`Nginx`對我們都開放了那些`API`。
參看下表:
| 名稱 | 說明 |
|-----|-----|
| $arg_name | 請求中的name參數 |
| $args | 請求中的參數 |
| $binary_remote_addr | 遠程地址的二進制表示 |
| $body_bytes_sent | 已發送的消息體字節數 |
| $content_length | HTTP請求信息里的"Content-Length" |
| $content_type | 請求信息里的"Content-Type" |
| $document_root | 針對當前請求的根路徑設置值 |
| $document_uri | 與$uri相同; 比如 /test2/test.php |
| $host | 請求信息中的"Host",如果請求中沒有Host行,則等于設置的服務器名 |
| $hostname | 機器名使用 gethostname系統調用的值 |
| $http_cookie | cookie 信息 |
| $http_referer | 引用地址 |
| $http_user_agent | 客戶端代理信息 |
| $http_via | 最后一個訪問服務器的Ip地址。 |
| $http_x_forwarded_for | 相當于網絡訪問路徑 |
| $is_args | 如果請求行帶有參數,返回“?”,否則返回空字符串 |
| $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 | 如果請求成功,設為"OK";如果請求未完成或者不是一系列請求中最后一部分則設為空 |
| $request_filename | 當前請求的文件路徑名,比如/opt/nginx/www/test.php |
| $request_method | 請求的方法,比如"GET"、"POST"等 |
| $request_uri | 請求的URI,帶參數; 比如[http://localhost:88/test1/](http://localhost:88/test1/) | test2/test.php |
| $scheme | 所用的協議,比如http或者是https |
| $server_addr | 服務器地址,如果沒有用listen指明服務器地址,使用這個變量將發起一次系統調用以取得地址(造成資源浪費) |
| $server_name | 請求到達的服務器名 |
| $server_port | 請求到達的服務器端口號 |
| $server_protocol | 請求的協議版本,"HTTP/1.0"或"HTTP/1.1" |
| $uri | 請求的URI,可能和最初的值有不同,比如經過重定向之類的 |
很多是吧,其實這還不是全部,`Nginx`一直在不停迭代更新是一個原因,還有一個原因是有些變量太冷門。使用它們,我們將會有很多玩法。
首先,我們在`OpenResty`中如何引用這些變量呢?參考[ngx.var.VARIABLE](http://wiki.nginx.org/HttpLuaModuleZh#ngx.var.VARIABLE)小節。
利用這些內置變量,來做一個簡單的數學求和運算例子:
~~~
server {
listen 8866;
server_name localhost;
location /sum {
#處理業務
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:8866/sum?a=11&b=12'
sum:23
~~~
也許你笑了,這個`API`太簡單了,貌似實際意義不大。我們做個最簡易的防火墻,貌似有就那么點意思了不是?
代碼如下:
~~~
server {
listen 8866;
server_name localhost;
location /sum {
# 使用access階段完成準入階段處理
access_by_lua '
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
';
#處理業務
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 )
}
}
}
~~~
測試 shell :
~~~
? ~ curl '192.168.1.104:8866/sum?a=11&b=12'
sum:23
? ~
? ~
? ~ curl '127.0.0.1:8866/sum?a=11&b=12'
403 Forbidden
403 Forbidden
openresty/1.9.3.1
~~~
通過測試結果看到,我們提取了終端的`IP`地址后進行限制,我們這個簡單防火墻就誕生了。稍微擴充一下,就可以做到支持范圍,如果再可以與系統`iptables`進行配合,那么達到軟防火墻的目的就沒有任何問題。
目前為止,我們所有的例子都是對`Nginx`內置變量的獲取,我們是否可以對其進行設置呢?其實大多數內容都是不允許寫入的,例如剛剛的終端`IP`地址,在應用中我們是不允許對其進行更新的。對于可寫的變量中的`limit_rate`,是值得一提的,他能完成傳輸速率限制。進一步說對于靜態文件傳輸、日志傳輸的情況,我們可以用它來完成限速的效果,它的影響是單個請求。
例如下面的例子:
~~~
location /download {
access_by_lua '
ngx.var.limit_rate = 1000
';
}
~~~
我們來下載這個文件:
~~~
? ~ wget '127.0.0.1:8866/download/1.cab'
--2015-09-13 13:59:51-- http://127.0.0.1:8866/download/1.cab
Connecting to 127.0.0.1:8866... 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
~~~
- 序
- Lua 入門
- Lua簡介
- Lua環境搭建
- 基礎數據類型
- 表達式
- 控制結構
- if/else
- while
- repeat
- for
- break,return
- Lua函數
- 函數的定義
- 函數的參數
- 函數的返回值
- 函數回調
- 模塊
- String庫
- Table庫
- 日期時間函數
- 數學庫函數
- 文件操作
- 元表
- 面向對象編程
- FFI
- 下標從1開始
- 局部變量
- 判斷數組大小
- 非空判斷
- 正則表達式
- 不用標準庫
- 虛變量
- 函數在調用代碼前定義
- 抵制使用module()函數來定義Lua模塊
- 點號與冒號操作符的區別
- Nginx
- Nginx 新手起步
- location 匹配規則
- if 是邪惡的
- 靜態文件服務
- 日志服務
- 反向代理
- 負載均衡
- 陷阱和常見錯誤
- 環境搭建
- Windows平臺
- CentOS平臺
- Ubuntu平臺
- Mac OS X平臺
- Hello World
- 簡單API Server框架
- 獲取Nginx內置綁定變量
- LuaRestyRedisLibrary
- select+set_keepalive組合操作引起的數據讀寫錯誤
- redis接口的二次封裝(簡化建連、拆連等細節)
- redis接口的二次封裝(發布訂閱)
- pipeline壓縮請求數量
- script壓縮復雜請求
- LuaCjsonLibrary
- json解析的異常捕獲
- 稀疏數組
- 空table編碼為array還是object
- 跨平臺的庫選擇
- PostgresNginxModule
- 調用方式簡介
- 不支持事務
- 超時
- 健康監測
- SQL注入
- LuaNginxModule
- 執行階段概念
- 正確的記錄日志
- 熱裝載代碼
- 阻塞操作
- 緩存
- sleep
- 定時任務
- 禁止某些終端訪問
- 請求返回后繼續執行
- 調試
- 調用其他C函數動態庫
- 我的lua代碼需要調優么
- 變量的共享范圍
- 動態限速
- shared.dict 非隊列性質
- 如何添加自己的lua api
- 正確使用長鏈接
- 如何引用第三方resty庫
- 典型應用場景
- LuaRestyDNSLibrary
- 使用動態DNS來完成HTTP請求
- 緩存失效風暴
- 測試
- 單元測試
- API測試
- 性能測試
- 持續集成
- 灰度發布
- Web 服務
- API的設計
- 數據合法性檢測
- 協議無痛升級
- 代碼規范
- 連接池
- C10K編程
- TIME_WAIT問題
- 與Docker使用的網絡瓶頸
- 火焰圖
- 什么時候使用
- 顯示的是什么
- 如何安裝火焰圖生成工具
- 如何定位問題
- 開源文化對360企業安全的影響