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 |
每個Nginx Worker進程啟動時調用的計時器,如果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 |
rrewrite階段處理,可以實現復雜的轉發/重定向邏輯; |
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階段處理,比如記錄訪問量/統計平均響應時間 |
更詳細的解釋請參考http://wiki.nginx.org/HttpLuaModule#Directives。
Nginx Lua API
官網文檔:https://www.nginx.com/resources/wiki/modules/lua/#nginx-api-for-lua
和一般的Web Server類似,我們需要接收請求、處理並輸出響應。而對於請求我們需要獲取如請求參數、請求頭、Body體等信息;而對於處理就是調用相應的Lua代碼即可;輸出響應需要進行響應狀態碼、響應頭和響應內容體的輸出。因此我們從如上幾個點出發即可。
接收請求
1、example.conf配置文件
location ~ /lua_request/(\d+)/(\d+) { #設置nginx變量 set $a $1; set $b $host; default_type "text/html"; #nginx內容處理 content_by_lua_file /usr/example/lua/test_request.lua; #內容體處理完成后調用 echo_after_body "ngx.var.b $b"; }
2、test_request.lua
--nginx變量 local var = ngx.var ngx.say("ngx.var.a : ", var.a, "<br/>") ngx.say("ngx.var.b : ", var.b, "<br/>") ngx.say("ngx.var[2] : ", var[2], "<br/>") ngx.var.b = 2; ngx.say("<br/>") --請求頭 local headers = ngx.req.get_headers() ngx.say("headers begin", "<br/>") ngx.say("Host : ", headers["Host"], "<br/>") ngx.say("user-agent : ", headers["user-agent"], "<br/>") ngx.say("user-agent : ", headers.user_agent, "<br/>") for k,v in pairs(headers) do if type(v) == "table" then ngx.say(k, " : ", table.concat(v, ","), "<br/>") else ngx.say(k, " : ", v, "<br/>") end end ngx.say("headers end", "<br/>") ngx.say("<br/>") --get請求uri參數 ngx.say("uri args begin", "<br/>") local uri_args = ngx.req.get_uri_args() for k, v in pairs(uri_args) do if type(v) == "table" then ngx.say(k, " : ", table.concat(v, ", "), "<br/>") else ngx.say(k, ": ", v, "<br/>") end end ngx.say("uri args end", "<br/>") ngx.say("<br/>") --post請求參數 ngx.req.read_body() ngx.say("post args begin", "<br/>") local post_args = ngx.req.get_post_args() for k, v in pairs(post_args) do if type(v) == "table" then ngx.say(k, " : ", table.concat(v, ", "), "<br/>") else ngx.say(k, ": ", v, "<br/>") end end ngx.say("post args end", "<br/>") ngx.say("<br/>") --請求的http協議版本 ngx.say("ngx.req.http_version : ", ngx.req.http_version(), "<br/>") --請求方法 ngx.say("ngx.req.get_method : ", ngx.req.get_method(), "<br/>") --原始的請求頭內容 ngx.say("ngx.req.raw_header : ", ngx.req.raw_header(), "<br/>") --請求的body內容體 ngx.say("ngx.req.get_body_data() : ", ngx.req.get_body_data(), "<br/>") ngx.say("<br/>")
ngx.var : nginx變量,如果要賦值如ngx.var.b = 2,此變量必須提前聲明;另外對於nginx location中使用正則捕獲的捕獲組可以使用ngx.var[捕獲組數字]獲取;
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體內容字符串。
如上方法處理一般的請求基本夠用了。另外在讀取post內容體時根據實際情況設置client_body_buffer_size和client_max_body_size來保證內容在內存而不是在文件中。
使用如下腳本測試:
wget --post-data 'a=1&b=2' 'http://127.0.0.1/lua_request/1/2?a=3&b=4' -O -
輸出響應
1.1、example.conf配置文件
location /lua_response_1 { default_type "text/html"; content_by_lua_file /usr/example/lua/test_response_1.lua; }
1.2、test_response_1.lua
ngx.header:輸出響應頭;
ngx.print:輸出響應內容體;
ngx.say:通ngx.print,但是會最后輸出一個換行符;
ngx.exit:指定狀態碼退出。
2.1、example.conf配置文件
2.2、test_response_2.lua
ngx.redirect:重定向;
ngx.status=狀態碼,設置響應的狀態碼;ngx.resp.get_headers()獲取設置的響應狀態碼;ngx.send_headers()發送響應狀態碼,當調用ngx.say/ngx.print時自動發送響應狀態碼;可以通過ngx.headers_sent=true判斷是否發送了響應狀態碼。
其他API
1、example.conf配置文件
2、test_other.lua
ngx.escape_uri/ngx.unescape_uri : uri編碼解碼;
ngx.encode_args/ngx.decode_args:參數編碼解碼;
ngx.encode_base64/ngx.decode_base64:BASE64編碼解碼;
ngx.re.match:nginx正則表達式匹配;
Nginx全局內存
使用過如Java的朋友可能知道如Ehcache等這種進程內本地緩存,Nginx是一個Master進程多個Worker進程的工作方式,因此我們可能需要在多個Worker進程中共享數據,那么此時就可以使用ngx.shared.DICT來實現全局內存共享。
1、首先在nginx.conf的http部分分配內存大小
#共享全局變量,在所有worker間共享
lua_shared_dict shared_data 1m;
2、example.conf配置文件
location /lua_shared_dict { default_type "text/html"; content_by_lua_file /usr/example/lua/test_lua_shared_dict.lua; }
3、 test_lua_shared_dict.lua
更多API請參考http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT。
Nginx Lua模塊指令
查看:
https://www.iteye.com/blog/jinnianshilongnian-2186448
https://www.cnblogs.com/JohnABC/p/6206622.html