1. 程式人生 > >Lua-Nginx-Module常用指令(下)

Lua-Nginx-Module常用指令(下)

十四、獲取Nginx的環境變數

通過Lua API可以獲取Nginx的環境變數,用來提升某些業務處理流程,比如有些定時任務只需要在一個worker程序上執行,不需要執行多次,因此可以獲取環境變數中worker的ID,在指定的ID上執行任務即可;或者獲取Nginx的worker程序是否正在shutdown,以決定是否對資料進行備份操作。

14.1 獲取環境所在的模組
ngx.config.subsystem
語法:subsystem = ngx.config.subsystem
配置環境:set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua,headerfilter

by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,init_by_lua,init_worker_by_lua

含義:獲取當前請求的Nginx子環境(http或stream)。如果在http模組下,就返回字串http;如果在stream模組下,則返回字串stream。

14.2 確認除錯模式
ngx.config.debug
語法:debug = ngx.config.debug
配置環境:set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua,headerfilter by_lua,body_filter_by_lua

,log_by_lua,ngx.timer.,init_by_lua,init_worker_by_lua

含義:判斷請求是否在Debug模式下執行。例如,當需要在Debug模式下,列印某些資料或是執行某些程式碼時,可以通過這個判斷,區分線下測試環境和線上環境。

14.3 獲取prefix路徑
ngx.config.prefix

語法:prefix = ngx.config.prefix()
配置環境:set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua,headerfilter by_lua,body_filter_by_lua,log_by_lua,ngx.timer.

,init_by_lua,init_worker_by_lua

含義:獲取編譯Nginx時--prefix=的路徑,如果啟動Nginx時使用了引數-p,就以引數-p的值為準。

14.4 獲取Nginx的版本號
ngx.config.nginx_version

語法:ver = ngx.config.nginx_version
配置環境:set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua,headerfilter by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,init_by_lua,init_worker_by_lua

含義:獲取Nginx的版本號,如本書使用的Nginx版本號是1.12.2。

14.5 獲取configure資訊
ngx.config.nginx_configure

語法:str = ngx.config.nginx_configure()
配置環境:set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua,headerfilter by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,init_by_lua*

含義:獲取編譯Nginx時./configure命令的資訊,返回的是一個字串。

14.6 獲取Ngx_Lua的版本號
ngx.config.ngx_lua_version
語法:ver = ngx.config.ngx_lua_version
配置環境:set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua,headerfilter by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,init_by_lua*

含義:獲取Ngx_Lua模組的版本號。可以用來檢查Ngx_Lua的版本。例如,當開發某個功能需要使用指定的版本時,可以在程式碼中進行判斷,如果不是指定的版本,可以輸出警告資訊。

14.7 判斷worker程序是否退出
ngx.worker.exiting
語法:exiting = ngx.worker.exiting()
配置環境:set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua,headerfilter by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,init_by_lua,init_worker_by_lua

含義:判斷Nginx的worker程序是否退出。

14.8 獲取worker程序的ID
ngx.worker.id
語法:count = ngx.worker.id()
配置環境:set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua,headerfilter by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,init_by_lua*

含義:獲取當前執行的worker程序的ID。worker程序的ID從0開始,依次遞增,最大值是worker總數的值減1。

14.9 獲取worker程序數量
ngx.worker.count
語法:count = ngx.worker.count()
配置環境:set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua,headerfilter by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,init_by_lua,init_worker_by_lua

含義:獲取當前Nginx worker程序的數量,即Nginx配置中worker_processes的值。

十五、定時任務

可以使用Nginx執行定時任務,例如,定期獲取MySQL資料庫中的資料並存放到共享記憶體中,定時監聽某個配置是否發生改變(如果發生改變就過載Nginx),定時將日誌遠端傳輸到集中儲存上等。
在Lua-0.10.9版本之前,常使用ngx.timer.at來啟動定時任務。Ngx_Lua 0.10.9新增了ngx.timer.every,啟動定時任務更加方便了。本章中的定時任務都使用ngx.timer.every來建立,後續介紹也會以此命令為主。

15.1 建立定時任務

ngx.timer.every
語法:hdl, err = ngx.timer.every(delay, callback, user_arg1, user_arg2, ...)
配置環境:init_worker_by_lua,set_by_lua,rewrite_by_lua,access_by_lua,content_ by_lua,header_filter_by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,balancerby lua,ssl_certificate_by_lua,ssl_session_fetch_by_lua,ssl_session_store_by_lua*
含義:建立一個定時任務,delay指的是延遲時間,表示每隔多少秒執行一次,支援配置0.001s,不支援配置0s;callback是需要執行的Lua函式,在Nginx退出時,定時任務會被關閉。

init_worker_by_lua_block {
    local delay = 3;
    local ngx = require "ngx";
    local check
    check = function(premature)
        if not premature then
         --輸出當前worker程序的PID和ID。
             ngx.log(ngx.ERR, ' ngx.worker.pid: ',ngx.worker.pid(),' ngx.worker.id: ',ngx.worker.id(),"------test nginx !!!")
        end
    end
    --每隔3s執行一次check函式
    local ok, err = ngx.timer.every(delay, check)
    if not ok then
         ngx.log(ngx.ERR, "failed to create timer: ", err)
         return
    end
}

過載Nginx配置後,定時任務會在啟動worker程序時就被觸發執行,請觀察圖7-1所示的定時任務輸出的日誌。

圖7-1 定時任務輸出的日誌
從圖7-1可以發現如下規則。

1.每個worker程序都在執行輸出操作。
2.都是每3s執行一次。
3.如果沒有從Nginx外部進行訪問的請求,定時任務會繼續執行下去。
引數user_arg1、user_arg2用來給定時任務傳遞引數,示例如下:

init_worker_by_lua_block {
    local delay = 3;
    local ngx = require "ngx";
    local check
    --新增一個u_arg1引數,是對下面定時任務的'test nginx'進行填充
    check = function(premature,u_arg1)
        if not premature then
            ngx.log(ngx.ERR, ' ngx.worker.pid: ',ngx.worker.pid(),' ngx.worker.id: ',ngx.worker.id(),'------', u_arg1)
        end
    end

    --新增引數'test nginx' 
    local ok, err = ngx.timer.every(delay, check, 'test nginx')
    if not ok then
        ngx.log(ngx.ERR, "failed to create timer: ", err)
        return
    end
}

配置7-1

15.2 效能優化

在配置7-1中,Nginx啟動了3個worker程序,所以每3s會執行3次worker程序。但有時只需執行一次即可,例如當前共享記憶體中存放資料時,因為資料是所有worker程序共享的,所以執行一次就足夠了。且被啟動的worker程序越多,後端的併發就越多,這會增加後端伺服器的負載,那麼應該怎麼減少worker程序重複執行的次數呢?
其實根據輸出的日誌可以獲得每個worker程序的ID,那麼,只需利用ID指定一個worker程序來執行定時任務就可以了,示例如下:

init_worker_by_lua_block {
     local delay = 3;
     local ngx = require "ngx";
     local check
     check = function(premature)
         if not premature then
             ngx.log(ngx.ERR, ' ngx.worker.pid: ',ngx.worker.pid(),' ngx.worker.id: ',ngx.worker.id(),"------test nginx !!!")
         end
     end

   --如果worker程序的ID為0就執行定時任務  
   if 0 == ngx.worker.id() then
         local ok, err = ngx.timer.every(delay, check)
         if not ok then
             ngx.log(ngx.ERR, "failed to create timer: ", err)
             return
         end
    end

}

觀察日誌,會發現每3s worker程序只執行一次。
如果worker程序意外終止,Nginx的master程序會保證在worker程序意外終止後重啟新的worker程序,ID保持不變。
如果要求定時任務只在Nginx過載時執行一次,可以使用如下方式:
local ok, err = ngx.timer.at(0,func)
這表示立即執行func函式,且由於沒有回撥ngx.timer.at的指令,只會執行一次。
注意:關於定時任務,需要在在init_worker_by_lua*的執行階段中執行(詳見8.2節)。

定時任務在Nginx後臺執行,不直接和客戶端請求打交道,因此不會直接影響請求的響應時間,但這並不代表它不會干擾請求的響應時間,如果在同一時間內有大量定時任務執行,也會降低Nginx的整體效能。此時,可以使用如下指令對正在執行的定時任務進行控制。
lua_max_running_timers
語法:lua_max_running_timers <count>
預設值:lua_max_running_timers 256
配置環境:http
含義:設定被允許的running timers(正在執行回撥函式的計時器)的最大數量,如果超過這個數量,就會丟擲“N lua_max_running_timers are not enough”,其中N是變數,指的是當前正在執行的running timers的最大數量。

lua_max_pending_timers
語法:lua_max_pending_timers <count>
預設值:lua_max_pending_timers 1024
配置環境:http
含義:設定允許使用的pending timers(執行掛起的定時器)的最大數量,如果在定時任務中超過這個限制,則會報“too many pending timers”錯誤。

15.3 禁用的Lua API
ngx.timer.every支援使用者操作共享記憶體、讀取資料庫資料、獲取系統時間等,但在定時任務中有些API是被明確禁止的,例如:
1.子請求ngx.location.capture。
2.向客戶端輸出的Lua API(如 ngx.say、ngx.print 和 ngx.flush)。
3.以ngx.req.開頭的Lua API。

十六、常用指令

Ngx_Lua提供了大量的Lua API指令來實現各種功能,本節會介紹一些常用的指令。

16.1 請求重定向
在Nginx中通過rewrite對請求進行重定向,而在Ngx_Lua裡可以使用ngx.redirect、ngx.req.set_uri來完成重定向,並且Ngx_Lua還提供了一個具有強大的擴充套件能力的ngx.exec指令。

ngx.redirect
語法:ngx.redirect(uri, status?)
配置環境:rewrite_by_lua,access_by_lua,content_by_lua*
含義:發出一個 HTTP狀態碼為301或302的重定向請求到指定的URI。
引數status的可選值有301、302、303、307和308,預設值是302。下面是ngx.redirect重定向和rewrite重定向的對比:

location / {
    # 等同於 rewrite ^/ http://testnginx.com/test? redirect;
    rewrite_by_lua_block {
        return ngx.redirect("/test")
    }
}

上述配置使用了預設的302狀態。如果在跳轉過程中需要保留請求的引數,可作如下配置:

location / {
    #  等同於 rewrite ^/ http://testnginx.com/test permanent;
    rewrite_by_lua_block {
        local ngx = require "ngx";
        return ngx.redirect("/test?" ..  ngx.var.args  ,301)
    }
}

也可以自定義引數,如下所示:

return ngx.redirect("/test?test=1&a=2" ,301)

支援跳轉到其他域名,如http://abc.testnginx.com:
return ngx.redirect("http://abc.testnginx.com",301)

注意:跳轉時都加return指令,其作用是為了強調跳轉操作,官方推薦使用這種方式。

ngx.req.set_uri
語法:ngx.req.set_uri (uri, jump?)
配置環境:set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua,headerfilter by_lua,body_filter_by_lua
含義:用引數uri來重寫當前的URL,和Nginx的rewrite內部重定向功能相似。例如,rewrite的指令rewrite ^ /test last; 與ngx.req.set_uri("/test", true)功能相似,而rewrite ^ /test break; 與ngx.req.set_uri("/foo", false)功能相似。
如果需要在跳轉過程中修改引數,可以使用ngx.req.set_uri_args來完成新的引數配置,操作如下:

ngx.req.set_uri_args("a=1&b=2&c=3")
ngx.req.set_uri("/test", true)

ngx.exec
語法:ngx.exec(uri, args?)
配置環境:rewrite_by_lua,access_by_lua,content_by_lua
含義:使用uri、args引數來完成內部重定向,類似於echo-nginx-module 的echo_exec指令。
示例:

server {
    listen       80;
    server_name  testnginx.com;
    default_type 'text/plain';
    location / {
        content_by_lua_block {
            return ngx.exec('/test');
        }
    }
    location /test {
        content_by_lua_block {
            ngx.say(ngx.var.args);
        }        
    }
}

下面是ngx_exec指令常用的幾種引數設定的示例。
保留之前的引數,如“ngx.exec('/test',ngx.var.args);”。
保留之前的引數,並新增引數,如“ngx.exec('/test' ,ngx.var.args .. 'd=4');”。
去掉之前的引數,並新增引數,如“ngx.exec('/test' , 'd=4');”。

注意:ngx_exec是一個內部重定向指令,不涉及外部的HTTP請求。在使用中推薦採用return ngx.exec(…)的方式。

16.2 日誌記錄
在使用Lua進行開發的過程中,需要使用日誌來輸出異常和除錯資訊,在Lua API中可以使用ngx.log來記錄日誌。
ngx.log
語法:ngx.log(log_level, ...)
配置環境:init_by_lua,init_worker_by_lua,set_by_lua,rewrite_by_lua,accessby lua,content_by_lua,header_filter_by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,balancer_by_lua,ssl_certificate_by_lua,ssl_session_fetch_by_lua,ssl_session_store_by_lua
含義:根據log_level的等級,將內容記錄到error.log的日誌檔案中。
log_level的級別及其說明見表7-6(和Nginx的error.log日誌級別是一致的)。
表7-6 log_level的級別及其說明

續表

示例:

server {
    listen       80;
    server_name  testnginx.com;
    default_type 'text/plain';
    location / {
        content_by_lua_block {
            ngx.say("test ")
            ngx.say("nginx ")
            ngx.log(ngx.ALERT, 'Log Test Nginx')
            ngx.log(ngx.STDERR, 'Log Test Nginx')
            ngx.log(ngx.EMERG, 'Log Test Nginx')
            ngx.log(ngx.ALERT, 'Log Test Nginx')
            ngx.log(ngx.CRIT, 'Log Test Nginx')
            ngx.log(ngx.ERR, 'Log Test Nginx')
            ngx.log(ngx.WARN, 'Log Test Nginx')
            ngx.log(ngx.NOTICE, 'Log Test Nginx')
            ngx.log(ngx.INFO, 'Log Test Nginx')
            ngx.log(ngx.DEBUG, 'Log Test Nginx')
        }
    }

}

執行結果如下:
curl -i 'http://testnginx.com/'
檢視error.log 日誌,預設在logs/error.log檔案中,示例如下:

2018/06/11 11:18:26 [alert] 1180#1180: *34 [lua] content_by_lua (nginx.conf:66):4: Log Test Nginx, client: 10.19.48.161, server: testnginx.com, request: "GET / HTTP/1.1", host: "testnginx.com"
2018/06/11 11:18:26 [] 1180#1180: *34 [lua] content_by_lua (nginx.conf:66):5: Log Test Nginx, client: 10.19.48.161, server: testnginx.com, request: "GET / HTTP/1.1", host: "testnginx.com"
2018/06/11 11:18:26 [emerg] 1180#1180: *34 [lua] content_by_lua (nginx.conf:66):6: Log Test Nginx, client: 10.19.48.161, server: testnginx.com, request: "GET / HTTP/1.1", host: "testnginx.com"
2018/06/11 11:18:26 [alert] 1180#1180: *34 [lua] content_by_lua (nginx.conf:66):7: Log Test Nginx, client: 10.19.48.161, server: testnginx.com, request: "GET / HTTP/1.1", host: "testnginx.com"
2018/06/11 11:18:26 [crit] 1180#1180: *34 [lua] content_by_lua (nginx.conf:66):8: Log Test Nginx, client: 10.19.48.161, server: testnginx.com, request: "GET / HTTP/1.1", host: "testnginx.com"
2018/06/11 11:18:26 [error] 1180#1180: *34 [lua] content_by_lua (nginx.conf:66):9: Log Test Nginx, client: 10.19.48.161, server: testnginx.com, request: "GET / HTTP/1.1", host: "testnginx.com"

觀察error.log日誌可發現,它並沒有輸出所有級別的日誌,這是因為Nginx中error.log的日誌級別會影響Lua中日誌的級別。如果將error.log的級別修改如下:
error_log /usr/local/nginx_1.12.2/logs/error.log info;
這樣Lua的日誌就可以列印到INFO級別了,如果需要DEBUG級別的日誌,重新編譯Nginx並開啟DEBUG模式即可。
ngx.log支援多個字串合併輸出,字串之間以逗號分隔,示例如下:
ngx.log(ngx.ERR, 'Log Test Nginx', 'a', 'b', 'c')
ngx.log單條日誌可輸出的最大位元組數受Nginx的限制,預設最多是2048個位元組,即2K。
Lua提供了print命令來簡化INFO級別的日誌的輸出。下面兩條語句的作用是一樣的:
print("Log Test Nginx ")
ngx.log(ngx.INFO, 'Log Test Nginx')
注意:ngx.print 和print 是兩條命令,不要混淆了。

16.3 請求中斷處理
在Lua中,可以對請求進行中斷處理,有兩種情況,如下:
1.中斷整個請求,則請求不再繼續執行,直接返回到客戶端。
2.中斷當前的執行階段,請求會繼續執行下一個階段,並繼續響應請求。
它們都是通過ngx.exit指令完成的。

ngx.exit
語法:ngx.exit(status)
配置環境:rewrite_by_lua,access_by_lua,content_by_lua,header_filter_by_lua,ngx.timer.,balancer_by_lua,ssl_certificate_by_lua,ssl_session_fetch_by_lua,sslsession store_by_lua
含義:引數status的值是HTTP的狀態碼。當引數status>=200時,請求會被中斷,並將status的值作為狀態值返回給Nginx。
當引數status==0時,請求會中斷當前的執行階段,繼續執行下一個階段(前提是還有下一個階段)。
配置環境:init_by_lua
,set_by_lua,rewrite_by_lua,access_by_lua,contentby lua,header_filter_by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,balancerby lua,ssl_certificate_by_lua,ssl_session_fetch_by_lua,ssl_session_store_by_lua
Ngx_Lua HTTP狀態碼清單見表7-9。
表7-9 Ngx_Lua HTTP狀態碼清單

續表

下面是一個HTTP狀態碼為0的示例:

server {
    listen       80;
    server_name  testnginx.com;
    default_type 'text/plain';
    location / {
        set $a  '0';
        rewrite_by_lua_block {
             ngx.var.a = '1';
             --等價於 ngx.exit(0), 0即HTTP狀態碼
             ngx.exit(ngx.OK)
        }
        echo $a;  #執行結果等於1 
    }
}

ngx.exit(ngx.OK)可以讓Nginx退出當前的rewrite_by_lua_block階段,繼續執行下面的階段,如上面程式碼中的echo。
如果想中斷當前的請求,不再繼續後面的執行階段,可以設定兩種退出狀態:
設定狀態碼大於或等於200且小於300,表示成功退出當前請求。
設定狀態碼大於或等於500,或其他異常的狀態,表示失敗退出當前請求。
繼續使用上面的例子,這次以非0的狀態碼退出當前請求,如下所示:

location / {
    set $a  '0';           
    rewrite_by_lua_block {
         ngx.var.a = '1';
         ngx.exit(200)  --也可以換成500,數字代表狀態碼的值
    }
         echo $a;  #沒有執行到這一句
}

因為使用了200狀態碼,所以請求在ngx.exit處被中斷後退出了,所以無法執行echo輸出的命令。為了強調退出操作,可以在此命令前加上return,如下所示:

return ngx.exit(ngx.OK)

十七、提升開發和測試效率

在使用Lua進行開發的過程中,可能需要頻繁修改Lua程式碼,預設情況下都需重啟Nginx才能使修改生效。使用lua_code_cache指令可以對其進行重新配置,並以此來提升開發效率。

語法:lua_code_cache on | off
預設:lua_code_cache on
配置環境:http,server,location,location if

含義:開啟或關閉_by_lua_file指定的Lua程式碼及Lua模組的快取。如果設定為off,則程式碼快取會被關閉,在_by_lua_file修改的程式碼不需要過載 Nginx配置就可以生效。

注意:此指令只適合用於_by_lua_file中的程式碼,不適用於 _by_lua_block 和 *_by_lua中的程式碼,因為這兩種指令的程式碼都是內嵌到Nginx配置檔案中的,必須通過reload配置檔案才可以使修改生效。把lua_code_cache設定為on只適合在開發環境中使用,不適合在線上環境中使用。

17.1 斷開客戶端連線
對於某些API請求,客戶端只管傳送並不等待返回結果,例如,觸發一個請求通知遠端服務端執行某個任務或進行日誌推送。此時,可以使用如下指令斷開連線。

ngx.eof
語法:ok, err = ngx.eof()
配置環境:rewrite_by_lua,access_by_lua,content_by_lua*
含義:顯示指定響應的輸出結束,會告知客戶端主動關閉連線,並在伺服器端繼續執行剩下的操作。

server {
    listen       80;
    server_name  testnginx.com;
    default_type 'text/plain';
    location / {
        set $a '0';
        content_by_lua_block {
            ngx.var.a = '1';
            --告知客戶端主動斷開連線
            ngx.eof()
            ngx.sleep(3);  --讓請求休眠3s。
            ngx.log(ngx.ERR, 'Test Nginx---',ngx.var.a)
        }
    }
}

執行curl -i 'http://testnginx.com/後,請求會立刻響應一個200狀態,表示響應內容已返回,但請求的後續操作仍在伺服器端繼續執行,3s後會將日誌寫入error.log
注意:執行完ngx.eof後,如果下一步是傳送子請求的指令,那麼,子請求會被意外中止,導致無法完成子請求的響應,這是受Nginx中proxy_ignore_client_abort預設值的影響,將proxy_ignore_client_abort設定為on,就可以在執行ngx.eof後繼續響應子請求了。

17.2 請求休眠

ngx.sleep
語法:ngx.sleep(seconds)
配置環境:rewrite_by_lua,access_by_lua,content_by_lua,ngx.timer.,sslcertificate by_lua,ssl_session_fetch_by_lua
含義:通過ngx.sleep命令可以在不阻塞Nginx worker程序的情況下,讓當前請求休眠指定時間(seconds),seconds最小值為0.001s。
示例:

location / {
    content_by_lua_block {
        --5秒後輸出ok。
        ngx.sleep(5);
        ngx.say('ok')
    }
}

17.3 獲取系統時間
在Ngx_lua中獲取系統時間,都是從Nginx的時間快取中讀取的,不涉及系統呼叫(系統呼叫的Lua命令類似於通過os.time獲取系統時間)。相關指令的配置環境都是相同的,都適用於如下執行階段。
init_worker_by_lua, set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua, ngx.timer., balancer_by_lua, ssl_certificate_by_lua, ssl_sessionfetch by_lua, ssl_session_store_by_lua*
在Ngx_lua中獲取系統時間的示例如下:

server {
    listen       80;
    server_name  testnginx.com;
    default_type 'text/plain';
    location / {
       content_by_lua_block {
            ngx.say('ngx.today: ',ngx.today())
            ngx.say('ngx.time: ',ngx.time())
            ngx.say('ngx.now: ',ngx.now())
            ngx.say('ngx.localtime: ',ngx.localtime())
            ngx.say('ngx.utctime: ',ngx.utctime())
            ngx.say('ngx.cookie_time: ',ngx.cookie_time(1528721405))
            ngx.say('ngx.parse_http_time: ',ngx.parse_http_time('Mon, 11-Jun-18 12:50:05 GMT'))
            ngx.say('ngx.update_time: ',ngx.update_time())
       }
    }
}

執行結果如下:
ngx.today: 2018-06-11 #返回系統的本地時間,只包含年、月、日
ngx.time: 1528721734 #返回當前時間的Unix時間戳
ngx.now: 1528721734.775 #返回當前時間的Unix時間戳,浮點數型別,小數部分是毫秒級別
ngx.localtime: 2018-06-11 20:55:34 #返回當前時間
ngx.utctime: 2018-06-11 12:55:34 #返回UTC(Coordinated Universal Time,即世界標準世界)時間
ngx.cookie_time: Mon, 11-Jun-18 12:50:05 GMT #返回一個可以讓Cookie過期的時間格式,引數是Unix時間戳格式
ngx.http_time: Mon, 11 Jun 2018 12:50:05 GMT #返回一個可以做HTTP頭部的時間格式,如expires或last-modified
ngx.parse_http_time: 1528721405 #返回Unix時間戳,和ngx.http_time輸出的時間格式不一樣
ngx.update_time: #返回空,作用是強行更新Nginx的時間快取,此操作會增加效能開銷,不建議使用

17.4 編碼與解碼
利用Ngx_Lua的API,可以進行編碼和解碼的操作。

ngx.escape_uri
語法:newstr = ngx.escape_uri(str)
配置環境:init_by_lua,init_worker_by_lua,set_by_lua,rewrite_by_lua,accessby lua,content_by_lua,header_filter_by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,balancer_by_lua,ssl_certificate_by_lua,ssl_session_fetch_by_lua,ssl_session_store_by_lua ngx.quote_sql_str
含義:對引數str進行URI編碼。

ngx.unescape_uri
語法:newstr = ngx.unescape_uri(str)
配置環境:init_by_lua,init_worker_by_lua,set_by_lua,rewrite_by_lua,accessby lua,content_by_lua,header_filter_by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,balancer_by_lua,ssl_certificate_by_lua
含義:對引數str進行URI解碼。

ngx.encode_args
語法:str = ngx.encode_args(table)
配置環境:set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua,headerfilter by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,balancer_by_lua,sslcertificate by_lua
含義:按照URI編碼規則,將Lua提供的table型別資料編碼成一個字串。

ngx.decode_args
語法:table, err = ngx.decode_args(str, max_args?)
配置環境:set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua,headerfilter by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,balancer_by_lua,ssl_certificateby lua,ssl_session_fetch_by_lua,ssl_session_store_by_lua
含義:將URI編碼的字串解碼為Lua的table型別的資料。

ngx.md5
語法:digest = ngx.md5(str)
配置環境:set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua,headerfilter by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,balancer_by_lua,ssl_certificateby lua,ssl_session_fetch_by_lua,ssl_session_store_by_lua
含義:對str字串進行MD5加密,並返回十六進位制的資料。

ngx.md5_bin
語法:digest = ngx.md5_bin(str)
配置環境:set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua,headerfilter by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,balancer_by_lua,ssl_certificateby lua,ssl_session_fetch_by_lua,ssl_session_store_by_lua
含義:對str字串進行MD5加密,並返回二進位制的資料。
注意:ngx.escape_uri和ngx.unescape_uri作用相反,ngx.encode_args和ngx.decode_args的作用相反。
關於編碼、解碼操作的示例如下:

server {
    listen       80;
    server_name  testnginx.com;
    default_type 'text/plain';
    location / {
       content_by_lua_block {
            local ngx = require "ngx";
            --對URI進行編碼
            ngx.say(ngx.var.uri, '---ngx.escape_uri---',ngx.escape_uri(ngx.var.uri))

            --對已經編碼過的URI進行解碼
            ngx.say('%2Ftest%2Fa%2Fb%2Fc', '---ngx.unescape_uri---',ngx.unescape_uri('%2Ftest%2Fa%2Fb%2Fc'))

            --將Lua的table型別資料編碼成字串
            local args_table_new =  ngx.encode_args({a = 1, b = 2, c = 3 })
            ngx.say('{a = 1, b = 2, c = 3 }', '---ngx.encode_args---' ,args_table_new)

            --對URI編碼的字串進行解碼,解碼成table型別的資料
            local args = ngx.var.args
            local args_table = ngx.decode_args(args)
            ngx.say(args, '---ngx.decode_args---', 'a=',args_table["a"])  --獲取table中的a的值
            --對URI進行MD5編碼,返回十六進位制資料
            ngx.say(ngx.var.uri, '---ngx.md5---',ngx.md5(ngx.var.uri))
            --對URI進行MD5編碼,返回二進位制資料   
            ngx.say(ngx.var.uri, '---ngx.md5_bin---',ngx.md5_bin(ngx.var.uri))
       }
    }
}

執行結果如下:


# curl  'http://testnginx.com/test/a/b/c?a=1&b=2&c=3'
/test/a/b/c---ngx.escape_uri---%2Ftest%2Fa%2Fb%2Fc
%2Ftest%2Fa%2Fb%2Fc---ngx.unescape_uri---/test/a/b/c
{a = 1, b = 2, c = 3 }---ngx.encode_args---b=2&a=1&c=3
a=1&b=2&c=3---ngx.decode_args---a=1
/test/a/b/c---ngx.md5---dfa371a9a8f52c9aadd016bda535fa43
/test/a/b/c---ngx.md5_bin---ߣq©¨