鍍金池/ 教程/ Java/ 使用 Nginx 內(nèi)置綁定變量
定時任務(wù)
函數(shù)的參數(shù)
超時
一個 openresty 內(nèi)存“泄漏”問題
獲取 uri 參數(shù)
局部變量
sleep
灰度發(fā)布
TIME_WAIT
代碼覆蓋率
連接池
CentOS 平臺安裝
稀疏數(shù)組
如何只啟動一個 timer 工作?
變量的共享范圍
break,return 關(guān)鍵字
Nginx
SQL 注入
如何引用第三方 resty 庫
不同階段共享變量
獲取請求 body
動態(tài)生成的 lua-resty-redis 模塊方法
動態(tài)加載證書和 OCSP stapling
repeat 控制結(jié)構(gòu)
編碼為 array 還是 object
Nginx 靜態(tài)文件服務(wù)
執(zhí)行階段概念
Lua 函數(shù)
日期時間函數(shù)
健康監(jiān)測
與其他 location 配合
for 控制結(jié)構(gòu)
函數(shù)定義
HTTPS 時代
點號與冒號操作符的區(qū)別
String 庫
文件操作
OpenResty 最佳實踐
<code>ngx.shared.DICT</code> 非隊列性質(zhì)
使用動態(tài) DNS 來完成 HTTP 請求
代碼規(guī)范
什么是 JIT?
Windows 平臺安裝
正確的記錄日志
LuaNginxModule
不用標準庫
C10K 編程
控制結(jié)構(gòu)
請求中斷后的處理
Lua 環(huán)境搭建
Test::Nginx 能指定現(xiàn)成的 nginx.conf,而不是自動生成一個嗎
Lua 基礎(chǔ)數(shù)據(jù)類型
動態(tài)限速
PostgresNginxModule
簡單API Server框架
API 測試
location 匹配規(guī)則
虛變量
單元測試
防止 SQL 注入
select + set_keepalive 組合操作引起的數(shù)據(jù)讀寫錯誤
阻塞操作
全動態(tài)函數(shù)調(diào)用
Web 服務(wù)
典型應(yīng)用場景
Nginx 新手起步
TLS session resumption
輸出響應(yīng)體
調(diào)用代碼前先定義函數(shù)
module 是邪惡的
怎樣理解 cosocket
模塊
Socket 編程發(fā)展
如何對 Nginx Lua module 添加新 api
如何在后臺開啟輕量級線程完成定時任務(wù)?
如何定位問題
table 庫
json 解析的異常捕獲
如何安裝火焰圖生成工具
lua 中如何 continue
if 是邪惡的
為什么我們的域名不能被解析
抵制使用 module() 定義模塊
測試
body 在 location 中的傳遞
Lua 入門
子查詢
pipeline 壓縮請求數(shù)量
如何發(fā)起新 HTTP 請求
Lua 簡介
緩存失效風(fēng)暴
Ubuntu 平臺安裝
日志輸出
緩存
Lua 面向?qū)ο缶幊?/span>
Nginx 陷阱和常見錯誤
Redis 接口的二次封裝(發(fā)布訂閱)
日志
訪問有授權(quán)驗證的 Redis
正則表達式
lock
熱裝載代碼
調(diào)用 FFI 出現(xiàn) &quot;table overflow&quot;
數(shù)據(jù)合法性檢測
禁止某些終端訪問
控制結(jié)構(gòu) if-else
調(diào)試
與 Docker 使用的網(wǎng)絡(luò)瓶頸
PostgresNginxModule 模塊的調(diào)用方式
用 do-end 整理你的代碼
FFI
什么時候使用
簡介
環(huán)境搭建
Mac OS X 平臺安裝
火焰圖
負載均衡
while 型控制結(jié)構(gòu)
如何定位 openresty 崩潰 bug
使用 Nginx 內(nèi)置綁定變量
判斷數(shù)組大小
請求返回后繼續(xù)執(zhí)行
Redis 接口的二次封裝
KeepAlive
反向代理
協(xié)議無痛升級
數(shù)學(xué)庫
元表
Vanilla 介紹
HelloWorld
LuaCjsonLibrary
持續(xù)集成
代碼靜態(tài)分析
網(wǎng)上有大量對 Lua 調(diào)優(yōu)的推薦,我們應(yīng)該如何看待?
script 壓縮復(fù)雜請求
非空判斷
性能測試
函數(shù)返回值
API 的設(shè)計
kong 介紹
表達式
不支持事務(wù)
LuaRestyDNSLibrary 簡介

使用 Nginx 內(nèi)置綁定變量

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