--[[
參考文檔: https://www.nginx.com/resources/wiki/modules/lua/#nginx-api-for-lua
Nginx Lua模塊指令:
Nginx共11個處理階段,而相應的處理階段是可以做插入式處理,即可插拔式架構;
另外指令可以在http、server、server if、location、location if幾個范圍進行配置:
指令: init_by_lua/init_by_lua_file
處理階段:
loading-config
使用范圍:
http
解釋:
nginx Master進程加載配置時執行;
通常用於初始化全局配置/預加載Lua模塊
指令: init_worker_by_lua/init_worker_by_lua_file
處理階段:
starting-worker
使用范圍:
http
解釋:
每個NginxWorker進程啟動時調用的計時器,
如果Master進程不允許則只會在init_by_lua之后調用;
通常用於定時拉取配置/數據,或者后端服務的健康檢查
指令: set_by_lua/set_by_lua_file
處理階段:
rewrite
使用范圍:
server,server if,location,location if
解釋:
設置nginx變量,可以實現復雜的賦值邏輯;此處是阻塞的,Lua代碼要做到非常快;
指令: rewrite_by_lua/rewrite_by_lua_file
處理階段:
rewrite tail
使用范圍:
http,server,location,location if
解釋:
rewrite階段處理,可以實現復雜的轉發/重定向邏輯;
指令: access_by_lua/access_by_lua_file
處理階段:
access tail
使用范圍:
http,server,location,location if
解釋:
請求訪問階段處理,用於訪問控制
指令: content_by_lua/content_by_lua_file
處理階段:
content
使用范圍:
location,location if
解釋:
內容處理器,接收請求處理並輸出響應
指令: header_filter_by_lua/header_filter_by_lua_file
處理階段:
output-header-filter
使用范圍:
http,server,location,location if
解釋:
設置header和cookie
指令:body_filter_by_lua/body_filter_by_lua_file
處理階段:
output-body-filter
使用范圍:
http,server,location,location if
解釋:
對響應數據進行過濾,比如截斷、替換。
指令:log_by_lua/log_by_lua_file
處理階段:
log
使用范圍:
http,server,location,location if
解釋:
log階段處理,比如記錄訪問量/統計平均響應時間
]]
ngx.var
-- nginx變量,如果要賦值如ngx.var.b = 2,此變量必須提前聲明;
-- 另外對於nginx location中使用正則捕獲的捕獲組可以使用ngx.var[捕獲組數字]獲取;
ngx.var.request_uri
-- 這個變量等於包含一些客戶端請求參數的原始URI,它無法修改,請查看$uri更改或重寫URI。
ngx.var.scheme -- ngx.var.server_addr
-- HTTP方法(如http,https)。按需使用
ngx.var.server_addruri
-- 服務器地址,在完成一次系統調用后可以確定這個值,如果要繞開系統調用,則必須在listen中指定地址並且使用bind參數。
ngx.var.uri
-- 請求中的當前URI(不帶請求參數,參數位於$args),可以不同於瀏覽器傳遞的$request_uri的值,它可以通過內部重定向,或者使用index指令進行修改。
ngx.var.server_name
-- 服務器名稱
ngx.var.server_port
-- 請求到達服務器的端口號。
ngx.var.remote_addr
-- 獲取遠程的IP地址
ngx.var.remote_port
-- 獲取遠程的端口號
ngx.header
-- 輸出響應頭;
ngx.print
-- 輸出響應內容體;
ngx.say
-- 通ngx.print,但是會最后輸出一個換行符;
ngx.exit
-- 指定狀態碼退出。
ngx.redirect
-- 重定向;
ngx.status = 301
-- 設置響應的狀態碼;
ngx.resp.get_headers()
-- 獲取設置的響應狀態碼;
ngx.send_headers()
-- 發送響應狀態碼, ,當調用ngx.say/ngx.print時自動發送響應狀態碼;
ngx.headers_sent = true
-- 判斷是否發送了響應狀態碼。
ngx.req.get_headers
-- 獲取請求頭,默認只獲取前100,如果想要獲取所以可以調用ngx.req.get_headers(0);
-- 獲取帶中划線的請求頭時請使用如headers.user_agent這種方式;
-- 如果一個請求頭有多個值,則返回的是table;
ngx.req.get_uri_args
-- 獲取url請求參數,其用法和get_headers類似;
ngx.req.get_post_args
-- 獲取post請求內容體,其用法和get_headers類似,但是必須提前調用ngx.req.read_body()來讀取body體
--(也可以選擇在nginx配置文件使用lua_need_request_body on;開啟讀取body體,但是官方不推薦);
ngx.req.raw_header
-- 未解析的請求頭字符串;
ngx.req.get_body_data
-- 為解析的請求body體內容字符串。
ngx.req.set_uri(uri, false)
-- 可以內部重寫uri(可以帶參數),等價於 rewrite ^ /lua_rewrite_3;
-- 通過配合if/else可以實現 rewrite ^ /lua_rewrite_3 break;
-- 這種功能;此處兩者都是location內部url重寫,不會重新發起新的
ngx.req.set_uri_args
-- 重寫請求參數,可以是字符串(a=1&b=2)也可以是table;
ngx.escape_uri
ngx.unescape_uri
-- uri編碼解碼;
ngx.encode_args
ngx.decode_args
-- 參數編碼解碼;
ngx.encode_base64
ngx.decode_base64
-- BASE64編碼解碼;
ngx.re.match
-- nginx正則表達式匹配;
ngx.timer.at
-- 延時調用相應的回調方法;
-- ngx.timer.at(秒單位延時,回調函數,回調函數的參數列表);
-- 可以將延時設置為0即得到一個立即執行的任務,任務不會在當前請求中執行不會阻塞當前請求,而是在一個輕量級線程中執行。
-- 指令: init_by_lua
--[[
nginx.conf配置文件中的http部分添加如下代碼,
#共享全局變量,在所有worker間共享
lua_shared_dict shared_data 1m;
init_by_lua_file /usr/example/lua/init.lua;
]]
--init.lua
--初始化耗時的模塊
local redis = require 'resty.redis'
local cjson = require 'cjson'
--全局變量,不推薦
count = 1
--共享全局內存
local shared_data = ngx.shared.shared_data
shared_data:set("count", 1)
-- test.lua
count = count + 1
ngx.say("global variable : ", count)
local shared_data = ngx.shared.shared_data
ngx.say(", shared memory : ", shared_data:get("count"))
shared_data:incr("count", 1)
ngx.say("hello world")
-- 訪問如http://192.168.1.2/lua 會發現全局變量一直不變,而共享內存一直遞增
-- global variable : 2 , shared memory : 8 hello world
-- 另外注意一定在生產環境開啟lua_code_cache,否則每個請求都會創建Lua VM實例。
-- 指令: init_worker_by_lua
--[[
用於啟動一些定時任務,比如心跳檢查,定時拉取服務器配置等等;
此處的任務是跟Worker進程數量有關系的,比如有2個Worker進程那么就會啟動兩個完全一樣的定時任務。
nginx.conf配置文件中的http部分添加如下代碼:
init_worker_by_lua_file /usr/example/lua/init_worker.lua;
另外根據實際情況設置如下指令
lua_max_pending_timers 1024; #最大等待任務數
lua_max_running_timers 256; #最大同時運行任務數
]]
-- init_worker.lua
local count = 0
local delayInSeconds = 3
local heartbeatCheck = nil
heartbeatCheck = function(args)
count = count + 1
ngx.log(ngx.ERR, "do check ", count)
local ok, err = ngx.timer.at(delayInSeconds, heartbeatCheck)
if not ok then
ngx.log(ngx.ERR, "failed to startup heartbeart worker...", err)
end
end
heartbeatCheck()
-- 指令: set_by_lua
--[[
設置nginx變量,我們用的set指令即使配合if指令也很難實現負責的賦值邏輯;
語法set_by_lua_file $var lua_file arg1 arg2...;
在lua代碼中可以實現所有復雜的邏輯,但是要執行速度很快,不要阻塞;
example.conf配置文件:
location /lua_set_1 {
default_type "text/html";
set_by_lua_file $num /usr/example/lua/test_set_1.lua;
echo $num;
}
]]
-- test_set_1.lua
local uri_args = ngx.req.get_uri_args()
local i = uri_args["i"] or 0
local j = uri_args["j"] or 0
return i + j
-- 訪問如http://192.168.1.2/lua_set_1?i=1&j=10進行測試。 如果我們用純set指令是無法實現的。