最近看了一些nginx+lua 的東西,嘗試實作了一下限流腳本,隻包含最根本的功能。
代碼如下
access_nginx_check.lua
-- 一個按照 url + 參數 進行 在固定時間内通路次數次數限制的lua 腳本,
-- 此處僅僅實作 按照url 10s 内限制 2次通路,記錄每次通路次數(無用僅僅用于核對代碼邏輯可去除),擷取參數函數已有,後續需要完善
--package.path = package.path ..';..\\?.lua';
--dofile ("./log.lua")
--是否開啟檢測
local check = "on"
--限制最大通路量
local count = 2
--限制時間範圍
local seconds = 10
--擷取參數的值
function getParam()
if "GET" == request_method then
args = ngx.req.get_uri_args()
elseif "POST" == request_method then
ngx.req.read_body()
args = ngx.req.get_post_args()
end
return args
end
--寫入日志
function writerLog(str)
local time = os.time()
local date = os.date("%Y%m%d",time)
local file = io.open("/var/www/lua/logTest/"..tostring(date).."_log.log","a")
--ngx.say("/var/www/lua/log/"..tostring(date).."_log.log")
--assert(file)
file:write(str.."\n")
file:close();
end
--對uri 進行限制主要邏輯
function access_user_uri_check()
-- body
if check=="on" then
local access_uri = ngx.var.host..ngx.var.uri
--local param = getParam()
local key = access_uri
--提前在nginx中聲明的變量
local limit = ngx.shared.limit
local req
if limit then
req ,_= limit:get(key)
end
if req then
if req>=count then
--超過限制之後傳回錯誤
ngx.say("您在最近:"..seconds.."秒,通路:"..access_uri.."次數超過:"..count.."次,已經觸發保護機制,請稍後通路")
ngx.exit(403)
end
--對key對應的資料進行累加
limit:incr(key,1)
else
--沒有值設定初始為1
limit:set(key,1,seconds)
end
--記錄log
writerLog(key..":"..limit:get(key))
end
end
--錯誤調試函數
function myerrorhandler( err )
ngx.say( "ERROR:", err )
end
--測試代碼,可以自動執行
status = xpcall( access_user_uri_check, myerrorhandler )
--access_user_uri_check()
對應nginx 配置
#聲明變量 對應lua 腳本中 的ngx.shared.limit
lua_shared_dict limit 10m;
server{
listen 80;
server_name localhost.accesslua.com;
root /var/www/html/test;
charset utf-8;
location ~\.php{
#為了調試lua腳本,直接将資訊抛出到浏覽器,否則會自動下載下傳
default_type 'text/html';
#嵌入的lua腳本
access_by_lua_file "/var/www/lua/access_nginx_check.lua";
#php 的正常調用
fastcgi_pass 192.168.33.11:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
#記錄log
access_log /usr/local/var/log/lua.accesslua-php5.access.log main;
}
示範效果