[code.openresty] Openresty指令集-上

指令集

Nginx和Lua最基本的構(gòu)建塊腳本是指令集涛酗。指令集用于確定什么時候用戶的Lua代碼運(yùn)行和結(jié)果將會被怎么使用畏邢。下面的圖顯示指令集的執(zhí)行順序暖释。

Lua Nginx 模塊指令集

lua_capture_error_log

語法: lua_capture_error_log size

默認(rèn):

上下文: http

用戶捕獲所有的nginx錯誤日志消息數(shù)據(jù)(并不是由本模塊或者nginx http子系統(tǒng)產(chǎn)生的纺弊,而是所有的)指定size的緩沖區(qū)而不使用文件或磁盤。

你可以在size值中使用計量單位如km蛋逾,如:

    lua_capture_error_log 100k;

根據(jù)經(jīng)驗來說骚腥,4kb緩沖區(qū)通常可以容納大約20個典型錯誤日志消息炸渡。所以自己算一下吧娜亿!

這個緩沖區(qū)永遠(yuǎn)不增長。如果它滿了蚌堵,新的錯誤日志消息會在這個緩沖區(qū)內(nèi)替代最老的那個买决。

緩沖區(qū)的大小必須大于單個錯誤日志消息的最大長度(在OpenResty里是4k,在一般的Nginx里是2k)吼畏。

你可以在Lua中通過lua-resty-core庫的ngx.errlog模塊的
get_logs()方法來讀取緩沖區(qū)中的消息督赤。這個Lua API方法將會返回捕獲的錯誤日志消息并且也移除這些已經(jīng)從全局捕獲緩沖區(qū)讀取的消息,為新的錯誤日志數(shù)據(jù)騰出空間泻蚊。出于這個原因躲舌,如果用戶讀取緩沖區(qū)的錯誤日志數(shù)據(jù)夠快的話,用戶不應(yīng)該將這個緩沖區(qū)配置的太大性雄。

注意没卸,error_log指令指定的日志級別標(biāo)準(zhǔn)的確對這個捕獲功能有影響。這個只會捕獲不低于在error_log指令中指定的日志級別的日志消息秒旋。
用戶還仍然可以通過Lua API函數(shù)errlog.set_filter_level選擇設(shè)置一個更高的過濾日志級別约计。
所以它比靜態(tài)的error_log指令更加靈活。

值得注意的是滩褥,如果在構(gòu)建OpenResty或Nginx時在./configure中沒有附帶--with-debug選項病蛉,那么是無法捕獲調(diào)試日志的。同時在構(gòu)建用于高開銷的產(chǎn)品是不提倡開啟調(diào)試日志。

這個指令首先在v0.10.9版本中被介紹铺然。

lua_use_default_type

語法: lua_use_default_type on | off

默認(rèn): lua_use_default_type on

上下文: http,server,location,location if

指定是否使用通過default_type指令指定的MIME類型作為響應(yīng)頭的Content-Type的默認(rèn)值俗孝。如果一個Lua請求處理程序的響應(yīng)頭的類型不想用默認(rèn)的Content-Type類型,那么禁用這個指令魄健。

這個指令在默認(rèn)情況下是開啟的赋铝。

這個指令在v0.9.1版本中被首先介紹。

lua_malloc_trim

語法: lua_malloc_trim <request-count>

默認(rèn): lua_malloc_trim 1000

上下文: http

由Nginx內(nèi)核處理每N個請求后沽瘦,告訴底層的libc運(yùn)行時間庫釋放它緩存的空閑內(nèi)存給操作系統(tǒng)革骨。默認(rèn)情況下,N是1000析恋。你可以用你自己的數(shù)字配置請求的數(shù)量良哲。比較小的數(shù)字意味著更加頻繁的釋放,這可能會導(dǎo)致更高的CPU時間消耗和更小的內(nèi)存占用助隧。同時比較大的數(shù)字通常會導(dǎo)致更少的CPU時間開銷和一個相對更大的內(nèi)存占用筑凫。
請根據(jù)你自己的使用情況來調(diào)整數(shù)字。

將參數(shù)配置為0會基本上完全關(guān)閉內(nèi)存整理并村。

  lua_malloc_trim 0; # 完全關(guān)閉內(nèi)存整理

當(dāng)前實現(xiàn)中使用Nginx日志處理程序來做請求計數(shù)巍实。所以在nginx.conf里出現(xiàn)log_subrequest on指令可能會在包含子請求的時候讓計數(shù)更快。默認(rèn)情況下哩牍,只統(tǒng)計主請求(main request)棚潦。

注意這個指令并會影響LuaJIT的分配器基于mmap系統(tǒng)調(diào)用的內(nèi)存空間。

這個指令在v0.10.7版本中被首先介紹膝昆。

lua_code_cache

語法: lua_code_cache on | off

默認(rèn): lua_code_cache on

上下文: http,server,location,location if

*_by_lua_file指令(如set_by_lua_file
content_by_lua_file)和Lua模塊中啟用或者禁用Lua代碼緩存丸边。

當(dāng)設(shè)置off時,每個通過ngx_lua處理的緩存會運(yùn)行在一個單獨的Lua VM實例外潜,從0.9.3版本開始原环。所以在set_by_lua_file,
content_by_lua_file, access_by_lua_file,等等引用的Lua文件將不會被緩存并且所有的被使用到的Lua模塊將會被從頭開始加載挠唆。有了這個处窥,開發(fā)人員可以采用edit-and-refresh方法。

不過請注意玄组,在nginx.conf里寫的內(nèi)聯(lián)Lua代碼例如這些set_by_lua, content_by_lua,
access_by_lua,和rewrite_by_lua指定的滔驾,在你修改了你nginx.conf文件里的內(nèi)聯(lián)Lua代碼之后將不會被更新嗡髓,這是因為只有Nginx配置文件解析器能正確解析nginx.conf文件并且唯一的方法是通過發(fā)送一個HUP信號來重新加載配置文件或者直接重啟Nginx扁眯。

即使是啟用了代碼緩存,在*_by_lua_file中通過dofileloadfile加載的Lua文件不能被緩存(除非你自己緩存那些結(jié)果)摄咆。通常你既可以使用init_by_lua或者 init_by_lua_file 指令來加載所有這些文件或者把這些Lu文件當(dāng)做真正的Lua模塊并且通過require加載他們患膛。

在Apachemod_lua模塊下摊阀,ngx_lua模塊并不支持stat模式可用。

在生產(chǎn)模式下,強(qiáng)烈不建議禁用Lua代碼緩存胞此,并且這個只能在開發(fā)時候使用臣咖,這是因為它對整體性能有很大的負(fù)面影響。例如漱牵,在禁用Lua代碼緩存之后夺蛇,“hello world”的Lua實例的性能表現(xiàn)會下降一個數(shù)量級。

lua_regex_cache_max_entries

語法: lua_regex_cache_max_entries <num>

默認(rèn): lua_regex_cache_max_entries 1024

上下文: http

指定在工作進(jìn)程級別編譯的正則表達(dá)式緩存允許的最大數(shù)量的條目酣胀。

ngx.re.match, ngx.re.gmatch, ngx.re.sub, 和 ngx.re.gsub中使用到的正則表達(dá)式會被緩存刁赦,如果指定了正則表達(dá)式選項o(例如,compile-once flag)

默當(dāng)?shù)竭_(dá)了這個限制是闻镶,默認(rèn)允許的條目數(shù)量是1024甚脉,新的正則表達(dá)式將不會被緩存(如果沒有指定o選項)并且這里會有一次,且只有一次铆农,在error.log文件中的警告信息:

2011/08/27 23:18:26 [warn] 31997#0: *1 lua exceeding regex cache max entries (1024), ...

如果你通過加載resty.core.regex模塊(或者僅僅resty.core模塊)來使用ngx.re.*實現(xiàn)lua-resty-core宦焦,那么這里使用的正則表達(dá)式緩存會是一個LRU緩存。

在動態(tài)生成的正則表達(dá)式中不要啟用o選項(并且/或 ngx.re.subngx.re.gsubreplace字符串參數(shù))顿涣,這會產(chǎn)生無限的變化以避免觸及指令的限制波闹。

lua_regex_match_limit

語法: lua_regex_match_limit <num>

默認(rèn): lua_regex_match_limit 0

上下文: http

在執(zhí)行ngx.re API指定被PCRE庫使用到的"match limit"。根據(jù)PCRE使用手冊涛碑,"這個限制 ... 對可以發(fā)生的回溯的限制數(shù)量有影響精堕。"

當(dāng)限制被命中,在Lua里面的ngx.re API方法會返回 "pcre_exec() failed: -8"錯誤字符串蒲障。

當(dāng)設(shè)置限制為0歹篓,編譯PCRE庫會使用默認(rèn)的“match limit”。并且這是這個指令默認(rèn)的值揉阎。

這個指令在v0.8.5版本中被首先介紹庄撮。

lua_package_path

語法: lua_package_path <lua-style-path-str>

默認(rèn): LUA_PATH環(huán)境變量或者Lua默認(rèn)編譯的內(nèi)容

上下文: http

設(shè)定在set_by_lua,
content_by_lua和其他指令的腳本中使用到的Lua模塊的搜索路徑。這是標(biāo)準(zhǔn)Lua形式中的路徑子字符串毙籽,并且;;可以被用來表示原來的搜索路徑洞斯。

v0.5.0rc29版本開始,特殊符號 $prefix or ${prefix}可以在搜索路徑字符串中使用來表明server prefix的路徑坑赡,而這個路徑通常是在啟動Nginx服務(wù)器時通過-p PATH命令號選項確定的烙如。

lua_package_cpath

語法: lua_package_cpath <lua-style-cpath-str&gt

默認(rèn): LUA_CPATH環(huán)境變量或者Lua默認(rèn)編譯的內(nèi)容

上下文: http

設(shè)定在set_by_lua,
content_by_lua和其他指令的腳本中使用到的Lua C模塊的搜索路徑。這個cpath路徑在標(biāo)準(zhǔn)Lua cpath形式毅否,并且;;可以被用來表示原始的的cpath亚铁。

v0.5.0rc29版本開始,特殊符號 $prefix or ${prefix}可以在搜索路徑字符串中使用來表明server prefix的路徑螟加,而這個路徑通常是在啟動Nginx服務(wù)器時通過-p PATH命令號選項確定的徘溢。

init_by_lua

語法: init_by_lua <lua-script-str>

上下文: http

時期: loading-config

注意v0.9.17版本之后不建議使用這個指令吞琐。使用 init_by_lua_block指令來代替。

當(dāng)Nginx主進(jìn)程(如果有的話)加載Nginx配置文件時然爆,在全局Lua VM級別通過指定參數(shù)<lua-script-str>來運(yùn)行Lua代碼顽分。

當(dāng)Nginx收到HUP信號并且開始重新加載配置文件,這個Lua VM也會被重新創(chuàng)建并且在新的Lua VM中init_by_lua會被重新執(zhí)行施蜜。如果 lua_code_cache 指令是關(guān)閉的(默認(rèn)開啟)卒蘸,這個init_by_lua處理器會在每個請求都運(yùn)行。這是因為在這個特殊模式下翻默,針對每個request請求缸沃,都會創(chuàng)建一個單獨的Lua VM。

通常情況下你可以注冊(true)Lua全局變量或者通過這個鉤子模塊在服務(wù)器啟動時預(yù)裝載Lua模塊修械。這里是預(yù)裝載Lua模塊的例子:


  init_by_lua 'cjson = require "cjson"';

  server{
      location = /api{
          content_by_lua_block {
              ngx.say(cjson.encode({dog = 5,cat = 6}))
          }
      }
  }

你也可以在這個階段初始化lua_shared_dict共享存儲器趾牧。這里是一個例子:


    lua_shared_dict dogs 1m;

    init_by_lua '
        local dogs = ngx.shared.dogs;
        dogs:set("Tom",56)
    ';

    server {
        location = /api {
            content_by_lua_block {
                local dogs = ngx.shared.dogs;
                ngx.say(dogs:get("Tom"))
            }
        }
    }

但是請注意,這個lua_shared_dict共享存儲區(qū)在配置文件重新加載時(例如:通過HUP信號)不會被清除肯污。所以如果你想在這個階段的init_by_lua代碼里面重新初始化共享存儲器翘单,那么你只需要在共享存儲器里面設(shè)置一個自定義標(biāo)記并且一直在你的init_by_lua代碼里面檢查這個標(biāo)記。

因為此上下文的Lua代碼在Nginx forks其工作進(jìn)程之前執(zhí)行(若有的話)蹦渣,這里加載的數(shù)據(jù)或代碼會享受很多操作系統(tǒng)在所有工作進(jìn)程中提供的Copy-on-write (COW)特性哄芜,從而節(jié)約了大量的內(nèi)存。

要在這個上下文中中初始化你自己的Lua全局變量柬唯,這是因為使用Lua全局變量會有性能損失并且會導(dǎo)致全局命名空間污染(參閱Lua Variable Scope章節(jié)查看詳情)认臊。推薦的方法是使用適當(dāng)?shù)?a target="_blank" rel="nofollow">Lua module文件(但是不要使用標(biāo)準(zhǔn)Lua方法module() 來定義Lua模塊因為它也會污染全局命名空間)并且調(diào)用require()init_by_lua或其他上下文中加載你自己的模塊文件。(require() 會緩存被加載的Lua模塊到在Lua注冊的全局package.loaded表中锄奢,所以你的模塊在整個Lua VM實例中只會被加載一次)失晴。

在這個上下文中,只有一小部分的Nginx API for Lua是被支持的:

在用戶的請求下涂屁,在未來更多的Nginx API可能會在此上下文中被支持。

基本上你可以在這個上下文中安全的使用Lua庫來做阻塞的I/O灰伟,這是因為在服務(wù)啟動時拆又,阻塞master進(jìn)程是完全可行的。甚至在配置加載階段Nginx內(nèi)核會做阻塞I/O(至少在解決upstream里面的host名稱時)袱箱。

你應(yīng)該在Lua代碼中非常小心潛在的安全漏洞遏乔,這是因為Nginx主進(jìn)程經(jīng)常在root賬號下啟動。

這個指令首先在v0.5.5版本中被介紹发笔。

init_by_lua_block

語法: init_by_lua_block { lua-script }

上下文: http

時期: loading-config

init_by_lua 指令相似,除了這個指令使用一對大括號({})替代Nginx字符串文字(需要特殊字符轉(zhuǎn)義)來包含Lua代碼凉翻。

例如:


init_by_lua_block{
      print("I need no extra escaping here, for example: \r\nblah")
}

這個指令首先在v0.9.17版本中被介紹了讨。

init_by_lua_file

語法: init_by_lua_file <path-to-lua-script-file>

上下文: http

時期: loading-config

init_by_lua等價,除了被<path-to-lua-script-file>指定的文件包含要被執(zhí)行的Lua代碼或者 Lua/LuaJIT bytecode

當(dāng)給出的是一個相對地址如foo/bar.lua前计,他們將會相對于 server prefix 轉(zhuǎn)化為絕對路徑胞谭, server prefix是在啟動Nginx服務(wù)器時通過-p PATH命令行參數(shù)指定的。

這個指令首先在v0.5.5版本中被介紹男杈。

init_worker_by_lua

語法: init_worker_by_lua <lua-script-str>

上下文: http

時期: starting-worker

注意v0.9.17開始 不建議 使用這個指令丈屹。使用init_worker_by_lua_block指令替代。

在Nginx主進(jìn)程啟用時伶棒,在每個Nginx工作進(jìn)程啟動時運(yùn)行指定的Lua代碼旺垒。當(dāng)主進(jìn)程被禁用時,這個鉤子將只會在 init_by_lua*之后運(yùn)行肤无。

這個鉤子經(jīng)常被用來創(chuàng)建每個工作進(jìn)程常有的定時器(通過ngx.timer.at Lua API)先蒋,為后端健康檢查或者其他日常工作。下面是例子宛渐,


    init_worker_by_lua '
          local delay = 3 -- in seconds
          local new_timer = ngx.timer.at
          local log = ngx.log
          local ERR = ngx.ERR
          local check

          check = function(premature)
                if no premature then
                    -- do the health check or other routine work
                    local ok,err = new_timer(delay,check)
                    if not ok then
                        log(ERR,"failed to create timer:",err)
                        return
                    end  
                end
          end

          local hd1,err = new_timer(delay,check)
          if not hd1 then
              log(ERR,"failed to create timer:",err)
              return
          end
    ';

這個指令首先在v0.9.5版本中被介紹過竞漾。

init_worker_by_lua_block

語法: init_worker_by_lua_block { lua-script }

上下文: http

時期: starting-worker

init_worker_by_lua指令相似,除了這個指令將Lua代碼直接通過一對大括號({})包含起來窥翩,代替Nginx字符串(需要特殊的字符轉(zhuǎn)義)

例如:


    init_worker_by_lua_block {
        print("I need no extra escaping here,for example:\r\nblah")
    }

這個指令首先在v0.9.17版本中被介紹业岁。

init_worker_by_lua_file

語法: init_worker_by_lua_file <lua-file-path>

上下文: http

時期: starting-worker

init_worker_by_lua相似,但是文件路徑接受一個Lua源碼文件或者Lua字節(jié)碼文件寇蚊。

這個指令首先在v0.9.5版本中被介紹叨襟。

set_by_lua

語法: set_by_lua $res <lua-script-str> [$arg1 $arg2 ...]

上下文: server,server if,location,location if

時期: rewite

注意v0.9.17版本開始 不建議 使用這個指令。使用 set_by_lua_block指令代替幔荒。

<lua-script-str>中指定的可執(zhí)行的Lua代碼和可選參數(shù)$arg1 $arg2 ...糊闽,并且返回字符串輸出給$res。在<lua-script-str>中的代碼可以執(zhí)行 API calls 并且可以從 ngx.arg 表(所以從1開始并且按順序增加)中檢索輸入?yún)?shù)爹梁。

這個指令是為了執(zhí)行短右犹、快速運(yùn)行的代碼塊,因為在代碼執(zhí)行過程中姚垃,Nginx事件循環(huán)是被阻塞的念链。應(yīng)該避免耗時的代碼序列。

這個指令是由注入到定制命令道標(biāo)準(zhǔn)的ngx_http_rewrite_module命令列表來實現(xiàn)的积糯。因為ngx_http_rewrite_module 在他的命令里面并不支持非阻塞I/O掂墓,在這個指令中,Lua API需要的暫停當(dāng)前Lua “l(fā)ight thread”不能工作看成。

至少在set_by_lua的上下文中下面的這些API方法目前是被禁用的君编。

另外,注意這個指令一次只能寫出一個Nginx變量值降瞳。然而嘱支,使用ngx.var.VARIABLE 接口是一個可行的解決方案。


    location /foo {
        set $diff ''; # 我們在這里需要已定義$diff變量

        set_by_lua $sum '
            local a = 32
            local b = 56

            ngx.var.diff = a - b; -- 直接寫到$diff
            return a + b; -- 正常的返回$sum值
        ';

        echo "sum = $sum,diff = $diff";
    }

這個指令可以和ngx_http_rewrite_module, set-misc-nginx-module, 和 array-var-nginx-module模塊的指令自由的組合挣饥。所有這些指令會按照他們在配置文件里面顯示的相同順序執(zhí)行除师。


    set $foo 32;
    set_by_lua $bar 'return tonumber(ngx.var.foo) + 1';
    set $baz "bar: $bar"; #$bar == “bar:33”

v0.5.0rc29版本開始,在這個指令的<lua-script-str>參數(shù)里面直接插入Nginx變量是被禁用的并且因此亮靴,dollar符號字符($)可以被直接使用馍盟。

這個指令需要ngx_devel_kit模塊。

set_by_lua_block

語法: set_by_lua_block $res { lua-script }

上下文: server,server if,location,location if

時期: rewrite

set_by_lua指令相似除了以下這些:

  1. 這個指令通過一對大括號({})將Lua源代碼直接包含起來茧吊,而不是使用Nginx字符串(需要特殊字符轉(zhuǎn)義)贞岭,并且
  2. 相比set_by_lua指令,這個指令并不支持Lua腳本之后的額外參數(shù)

例如:


  set_by_lua_block $res {return 32 + math.cos(32)}
  # $res 現(xiàn)在有"32.834223360507"或者類似的值

在這個Lua代碼塊中不需要特殊的轉(zhuǎn)義搓侄。

這個指令從v0.9.17版本被首先介紹瞄桨。

set_by_lua_file

語法: set_by_lua_file $res ?path-to-lua-script-file> [$arg1 $arg2 ...]

上下文: server,server if,location,location if

時期: rewrite

set_by_lua等價,除了在<path-to-lua-script-file>中指定包含Lua代碼的文件讶踪,或者芯侥,從v0.5.0rc32版本,Lua/LuaJIT bytecode被排除了乳讥。

在這個指令的<path-to-lua-script-file>參數(shù)字符串中柱查,Nginx變量插入是支持的。但是必須特別注意注入攻擊云石。

當(dāng)給出一個類似foo/bar.lua的相對路徑唉工,它們會相對server prefix路徑來變成絕對路徑,這個變量是通過在啟動Nginx服務(wù)器時在命令行中定義的-p PATH參數(shù)定義的汹忠。

當(dāng)Lua代碼緩存被打開后(默認(rèn)情況下)淋硝,用戶的代碼會在第一次請求的時候被加載并且被緩存并且再Lua源碼文件被修改后Nginx配置必須被重新加載。

在開發(fā)時可以臨時的將Lua代碼緩存通過在nginx.conf里轉(zhuǎn)換lua_code_cacheoff禁用掉宽菜,從而避免重啟Nginx谣膳。

這個指令需要ngx_devel_kit模塊。

content_by_lua

語法: content_by_lua <lua-script-str>

上下文: location,location if

時期: content

注意v0.9.17版本開始铅乡,不建議 使用這個指令继谚,使用 content_by_lua_block指令代替。

作為一個“內(nèi)容處理程序”執(zhí)行并且在每個請求中執(zhí)行<lua-script-str>中指定的Lua代碼字符串隆判。
其中的Lua代碼可以執(zhí)行API calls并且將會在一個獨立的全局環(huán)境(例如犬庇,一個沙箱)中作為一個新的子協(xié)同程序被執(zhí)行僧界。

不要在同一個location中使用這個指令和其他內(nèi)容處理程序指令侨嘀。例如:這個指令和proxy_pass 指令不能再同一個location中被同時使用臭挽。

content_by_lua_block

語法: content_by_lua_block { lus-script }

上下文: location,location if

時期: content

content_by_lua指令相似除了這個指令通過一對大括號 ({}) 將Lua源碼包含進(jìn)去而不是Nginx字符串(需要特殊的字符轉(zhuǎn)義)

例如,


    content_by_lua_block {
        ngx.say("I need no extra escaping here, for example: \r\nblah")
    }

這個指令首先從v0.9.17版本開始被介紹咬腕。

content_by_lua_file

語法: content_by_lua_file <path-to-lua-script-file>

上下文: locaiton,location if

時期: content

content_by_lua相似欢峰,除了<path-to-lua-script-file>指定包含Lua代碼的文件,或者涨共,從v0.5.0rc32版本開始纽帖,Lua/LuaJIT bytecode 被排除了。

Nginx變量可以在<path-to-lua-script-file>字符串中使用以提供靈活性举反。然而這會帶來一些風(fēng)險懊直,不被推薦。

當(dāng)給出一個相對路徑例如foo/bar.lua時火鼻,它們會相對server prefix路徑轉(zhuǎn)換成為絕對路徑室囊,server prefix在Nginx服務(wù)器啟動時通過-p PATH參數(shù)指定。

當(dāng)Lua代碼緩存被啟用(默認(rèn))魁索,在第一次請求時用戶代碼會被加載并緩存并且當(dāng)Lua源文件被修改后Nginx配置必須被重新加載融撞。

在開發(fā)時可以臨時的將Lua代碼緩存通過在nginx.conf里轉(zhuǎn)換lua_code_cacheoff禁用掉,從而避免重啟Nginx粗蔚。

為了動態(tài)調(diào)度尝偎,文件路徑中支持Nginx變量,例如:


    # 注意:內(nèi)容中的nginx變量必須被小心的過濾掉鹏控。
    # 否則會有嚴(yán)重的安全風(fēng)險致扯。
    location ~ ^/app/([-_a-zA-Z0-9/]+) {
        set $path $1;
        content_by_lua_file /path/to/lua/app/root/$path.lua;
    }

但是要非常小心惡意用戶輸入并且總要仔細(xì)驗證或過濾掉用戶提供的路徑部分。

rewrite_by_lua

語法: rewrite_by_lua <lua-script-str>

上下文: http,server,location,location if

時期: rewrite tail

注意 這個指令在v0.9.17版本之后 不建議 被使用当辐。使用rewrite_by_lua_block指令代替抖僵。

作為rewite階段處理程序使用并且為每個請求執(zhí)行<lua-script-str>中的Lua代碼字符串。Lua代碼可以執(zhí)行 API calls 并且會在一個獨立的全局環(huán)境(如:沙箱)中作為一個新的子協(xié)同程序執(zhí)行瀑构。

注意這個處理程序經(jīng)常在標(biāo)準(zhǔn)ngx_http_rewrite_module 之后 執(zhí)行裆针,所以下面的會按照預(yù)期工作:


    location /foo {
        set $a 12; # 創(chuàng)建并初始化$a
        set $b ""; # 創(chuàng)建并初始化$b
        rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'
        echo "res = $b"
    }

這是因為 set $a 12set $b ""rewrite_by_lua 之前 執(zhí)行。

另一方面寺晌,下面的不會按照預(yù)期執(zhí)行:


?  location /foo {
?      set $a 12; # create and initialize $a
?      set $b ''; # create and initialize $b
?      rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1';
?      if ($b = '13') {
?         rewrite ^ /bar redirect;
?         break;
?      }
?
?      echo "res = $b";
?  }

這是因為 if會在rewrite_by_lua 之前 執(zhí)行世吨,即使在配置文件里面它被放置在rewrite_by_lua之后。

正確實現(xiàn)如下:


    location /foo {
        set $a 12; # 創(chuàng)建并實例化 $a
        set $b ''; # 創(chuàng)建并實例化 $b
        rewrite_by_lua '
            ngx.var.b = tonumber(ngx.var.a) + 1
            if tonumber(ngx.var.b) == 13 then
                return ngx.redirect("/bar");
            end
        ';

        echo "res = $b";
    }

注意ngx_eval模塊可以通過使用rewrite_by_lua來近似出來呻征。例如:


    location / {
        eval $res {
            proxy_pass http://foo.com/ehck-span;
        }

        if ($res = 'spam') {
            rewrite ^ /terms-of-use.html redirect;
        }

        fastcgi_pass ...;
    }

可以在ngx_lua如下實現(xiàn):


      location = /check-spam{
          internal;
          proxy_pass http://foo.com/check-spam
      }

      location / {
          rewrite_by_lua'
                local res = ngx.location.capture("/check-spam")
                if res.body == "spam" then
                    return ngx.redirect("/terms-of-use.html")
                end
          ';

          fastcgi_pass ...;
      }

和其他rewrite階段處理程序一樣耘婚,rewrite_by_lua同樣也在子請求中運(yùn)行。

注意當(dāng)在rewrite_by_lua處理程序里面調(diào)用ngx.exit(ngx.OK)時陆赋,nginx內(nèi)容處理程序的請求處理控制流仍然能繼續(xù)沐祷。要終止從rewrite_by_lua處理器內(nèi)部的當(dāng)前請求嚷闭,以status >= 200(ngx.HTTP_OK) 和 status < 300(ngx.HTTP_SPECIAL_RESPONSE)調(diào)用ngx.exit來處理成功退出,使用ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)(或其朋友)處理失敗赖临。

如果ngx_http_rewrite_modulerewrite指令被用來更改URI和啟動location re-lookups(內(nèi)部重定向)胞锰,那么著當(dāng)前l(fā)ocation里的任何 rewrite_by_lua或者rewrite_by_lua_file 代碼序列將不會被執(zhí)行。例如:


    location /foo {
        rewite ^ /bar;
        rewrite_by_lua 'ngx.exit(503)';
    }
    location /bar {
        ...
    }

這里的Lua代碼ngx.exit(503)將永遠(yuǎn)不會被執(zhí)行兢榨。這是因為如果rewrite ^ /bar last被使用了的話這里將會啟動一個內(nèi)部重定向嗅榕。如果使用break修飾語,這里將不會有內(nèi)部重定向并且rewrite_by_lua代碼塊將會被執(zhí)行吵聪。

這個rewrite_by_lua代碼將會一直在rewrite請求處理階段之后執(zhí)行除非rewrite_by_lua_no_postpone被開啟凌那。

rewrite_by_lua_block

語法: rewrite_by_lua_block { lua-script }

上下文: http,server,location,location if

時期: rewrite tail

rewrite_by_lua指令相似除了這個指令通過一對大括號({})來直接包含Lua代碼而不是使用Nginx字符串(需要特殊字符轉(zhuǎn)義)

例如,


    rewrite_by_lua_block {
        do_something("hello, world!\nhiya\n")
    }
  

這個指令首先從 v0.9.17版本被介紹吟逝。

rewrite_by_lua_file

語法: rewrite_by_lua_file <path-to-lua-script-file>

上下文: http,server,location,location if

時期: rewrite tail

rewrite_by_lua等價帽蝶,除了<path-to-lua-script-file>指定包含Lua代碼的文件,或者块攒,從v0.5.0rc32版本励稳,Lua/LuaJIT bytecode被排除了。

Nginx變量可以在 <path-to-lua-script-file>字符串中被使用以提供靈活性局蚀。但是這會增加一些風(fēng)險并且一般不推薦麦锯。

當(dāng)給出以一個相對地址如foo/bar.lua,它們會相對server prefix地址轉(zhuǎn)成絕對地址琅绅,server prefix在Nginx服務(wù)器啟動時通過命令行選項-p PATH來定義扶欣。

當(dāng)Lua代碼緩存被開啟(默認(rèn)),用戶的代碼會在第一次請求時被加載并且被緩存千扶,如果Lua代碼文件被修改了那么Nginx配置必須被重新加載料祠。在開發(fā)時,可以臨時的關(guān)閉Lua代碼緩存來避免重啟Nginx澎羞,通過將nginx.conf里的lua_code_cache轉(zhuǎn)換為off髓绽。

rewrite_by_lua_file代碼會一直在rewrite請求處理階段結(jié)束后執(zhí)行除非rewrite_by_lua_no_postpone被開啟。

為了在content_by_lua_file里支持動態(tài)調(diào)度妆绞,文件路徑中支持Ngixn變量顺呕。

access_by_lua

語法: access_by_lua <lua-script-str>

上下文: http,server,location,location if

時期: access tail

注意v0.9.17版本之后 不建議 使用這個指令。使用access_by_lua_block指令代替括饶。

作為訪問階段處理程序執(zhí)行并且為每個請求執(zhí)行<lua-script-str>指定的Lua代碼株茶。
Lua代碼可以執(zhí)行API calls并且它在一個獨立的全局環(huán)境(如:沙箱)里作為一個子協(xié)同程序執(zhí)行。

注意這個處理器一直在標(biāo)準(zhǔn)的ngx_http_access_module 之后 運(yùn)行图焰。所以下面的會按照預(yù)期執(zhí)行:


    location / {
        deny 192.168.1.1;
        allow 192.168.1.0/24;
        allow 10.1.1.0/16;
        deny all;

        access_by_lua '
            local res = ngx.location.capture("/mysql",{...})
            ...
        ';

        # proxy_pass/fastcgi_pass/...
    }

就是說启盛,如果一個客戶端IP在黑名單內(nèi),它被在MySQL查詢之前被阻止,對更加復(fù)雜的身份認(rèn)證是用access_by_lua執(zhí)行的僵闯。

注意可以使用access_by_lua來近似ngx_auth_request模塊卧抗。


    location / {
        auth_request /auth;
        # proxy_pass/fastcgi_pass/postgres_pass/...
    }
  

可以被ngx_lua實現(xiàn)如下:


    location / {
        access_by_lua '
            local res = ngx.location.capture("/auth")

            if res.status == ngx.HTTP_OK then
                return
            end

            if res.status == ngx.HTTP_FORBIDDEN then
                ngx.exit(res.status)
            end

            ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
        ';

        # proxy_pass/fastcgi_pass/postgres_pass/...
    }

正如其他訪問階段處理程序,access_by_lua不會 在子請求中被執(zhí)行。

注意當(dāng)在access_by_lua處理程序里面調(diào)用ngx.exit(ngx.OK)時鳖粟,nginx內(nèi)容處理程序的請求處理控制流仍然能繼續(xù)社裆。要終止從access_by_lua處理器內(nèi)部的當(dāng)前請求,以status >= 200(ngx.HTTP_OK) 和 status < 300(ngx.HTTP_SPECIAL_RESPONSE)調(diào)用ngx.exit來處理成功退出牺弹,使用ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)(或其朋友)處理失敗浦马。

v0.9.20版本開始时呀,你可以使用access_by_lua_no_postpone指令來控制在Nginx的"accesss"請求處理階段什么時候運(yùn)行這個處理器张漂。

access_by_lua_block

語法: access_by_lua_block { lua-script }

上下文: http,server,location,location if

階段: access tail

access_by_lua指令相似,除了這個指令通過一對大括號({})直接包含其中的Lua代碼谨娜,而不是使用Nginx字符串(需要特殊字符轉(zhuǎn)碼)

例如:


    access_by_lua_block{
        do_something("hello, world!\nhiya\n")
    }
    

這個指令首先在v0.9.17版本中被介紹航攒。

access_by_lua_file

語法: access_by_lua_file <path-to-lua-script-file>

上下文: http,server,location,location if

階段: access tail

access_by_lua等價,除了<path-to-lua-script-file>指定包含Lua代碼的文件趴梢,或者漠畜,從 v0.5.0rc32版本開始,Lua/LuaJIT bytecode 被排除了坞靶。

<path-to-lua-script-file>字符串中可以使用Nginx變量以提供靈活性憔狞。然而這回增加風(fēng)險而且一般不建議使用。

當(dāng)給出一個類似foo/bar.lua的相對路徑彰阴,它們會相對server prefix路徑來變成絕對路徑瘾敢,這個變量是通過在啟動Nginx服務(wù)器時在命令行中定義的-p PATH參數(shù)定義的。

當(dāng)Lua代碼緩存被打開后(默認(rèn)情況下)尿这,用戶的代碼會在第一次請求的時候被加載并且被緩存并且再Lua源碼文件被修改后Nginx配置必須被重新加載簇抵。

在開發(fā)時可以臨時的將Lua代碼緩存通過在nginx.conf里轉(zhuǎn)換lua_code_cacheoff禁用掉,從而避免重啟Nginx射众。

content_by_lua_file中為了實現(xiàn)動態(tài)調(diào)度碟摆,文件路徑里面支持Nginx變量。

header_filter_by_lua

語法: header_filter_by_lua <lua-script-str>

上下文 http,server,location,location if

時期 output-header-filter

注意v0.9.17版本之后 不建議 使用該指令叨橱。使用header_filter_by_lua_block指令代替

使用<lua-script-str>指定的Lua代碼來定義一個輸出header的過濾器典蜕。

注意在此上下文中下面的API方法目前是禁用的:

這里是在我們的Lua header過濾器中重寫響應(yīng)header的一個例子(如果為空則是添加)


  location / {
      proxy_pass http://mybackend;
      header_filter_by_lua 'ngx.header.Foo = "blah"';
  }

這個指令首先在v0.2.1rc20版本中被介紹。

header_filter_by_lua_block

語法: header_filter_by_lua_block { lua-script }

上下文: http,server,location,location if

時期: output-header-filter

header_filter_by_lua指令相似除了這個指令將Lua代碼直接包含在一對大括號({})之內(nèi)而不是Nginx字符串(需要特殊的字符轉(zhuǎn)碼)罗洗。

例如愉舔,


    header_filter_by_lua_block{
      ngx.header["content-length"] = nil
    }

這個指令首先在 v0.9.17版本中被介紹。

header_filter_by_lua_file

語法: header_filter_by_lua_file <path-to-lua-script-file>

時期: http,server,location,location if

階段: output-header-filter

header_filter_by_lua等價栖博,除了通過<path-to-lua-script-file指定的文件包含Lua代碼屑宠,或者,從 v0.5.0rc32 版本仇让, Lua/LuaJIT bytecode被排除了典奉。

當(dāng)給定一個相對路徑如foo/bar.lua躺翻,它們會相對server prefix轉(zhuǎn)化為絕對路徑,server prefix路徑在Nginx服務(wù)器啟動時通過命令行里面的-p PATH參數(shù)指定卫玖。

這個指令在v0.2.1rc20版本時被首先介紹公你。

body_filter_by_lua

語法: body_filter_by_lua <lua-script-str>

上下文: http,server,location,location if

時期: output-body-filter

注意:v0.9.17版本開始 不建議 使用這個指令。使用body_filter_by_lua_block指令來代替假瞬。

通過<lua-script-str>指令指定的Lua代碼定義一個輸出body過濾器

輸出數(shù)據(jù)塊通過ngx.arg[1]來傳遞(作為一個Lua字符串值)并且標(biāo)志響應(yīng)body數(shù)據(jù)流結(jié)束的"eof"標(biāo)記通過ngx.arg[2]來傳遞(作為一個Lua boolean值)陕靠。

在幕后,“eof”標(biāo)記就是在Nginx鏈條的緩沖區(qū)的last_buf(在主請求中)或者last_in_chain(在子請求中)標(biāo)記脱茉。(在 v0.7.14版本之前剪芥,"eof"標(biāo)記在所有的子請求中不起效)

輸出數(shù)據(jù)流可以通過運(yùn)行下面的Lua語句立即中止:

    return ngx.ERROR

這個將截斷響應(yīng)體并且通常情況下導(dǎo)致不完整也無效的響應(yīng)。

Lua代碼可以將它自己修改過的輸入數(shù)據(jù)塊傳送給下游的Nginx輸出body過濾器中琴许,通過用一個Lua字符串或包含字符串的Lua table重寫ngx.arg[1]税肪。例如:在response body里面轉(zhuǎn)換所有的小寫字母,我們可以這樣寫:


    location / {
        proxy_pass http://mybackend;
        body_filter_by_lua 'ngx.arg[1] = string.upper(ngx.arg[1])';
    }

當(dāng)設(shè)置為nil或者一個空Lua字符串給ngx.arg[1]榜田,沒有數(shù)據(jù)塊會被傳輸?shù)絅ginx下游的輸出過濾器益兄。

同樣的,新的"eof"標(biāo)記可以通過設(shè)置一個boolean值給ngx.arg[2]來指定箭券。例如:


    location /t {
        echo hello world;
        echo hiya globe;
        body_filter_by_lua '
              local chunk = ngx.arg[1]
              if string.match(chunk,"hello") then
                    ngx.arg[2] = true -- new eof
              end

              -- just throw away any remaining chunk data
              ngx.arg[1] = nil
        ';
    }

然后 GET /t只會返回輸出:

hello world

也就是說净捅,當(dāng)body過濾器發(fā)現(xiàn)一塊包含單詞"hello",那么它會立即將"eof"標(biāo)記設(shè)置為true,導(dǎo)致了一個截斷但仍然有效的回復(fù)辩块。

Lua代碼有時會改變響應(yīng)的body的長度蛔六,那么它應(yīng)該經(jīng)常的在頭過濾器中清除Content-Length響應(yīng)頭(如果可能的話)來強(qiáng)制流輸出,例如:

    location /foo {
          # fastcgi_pass/proxy_pass/...

          header_filter_by_lua_block { ngx.header.content_length = nil}
          body_filter_by_lua 'ngx.arg[1] = string.len(ngx.arg[1]) .. "\\n"';
    }

注意在此上下文中下面的API方法目前是被禁用的庆捺,這是由于目前Nginx輸出過濾器當(dāng)前實現(xiàn)的的限制古今。

Nginx輸出過濾器可能在一個請求中被調(diào)用多次,因為response body可能被分段傳送滔以。因此捉腥,這個指令指定的Lua代碼可能也會在一個HTTP request的生命周期中被執(zhí)行多次。

這個指令首先從v0.5.0rc32版本被介紹你画。

body_filter_by_lua_block

語法: body_filter_by_lua_block { lua-script-str }

上下文: http,server,location,location if

時期: output-body-filter

body_filter_by_lua指令相似除了這個指令將Lua代碼直接包含在一對大括號 ({}) 里面而不是Nginx字符串(需要特殊字符轉(zhuǎn)碼)

例如抵碟,


    body_filter_by_lua_block{
          local data,eof = ngx.arg[1],ngx.arg[2]
    }

這個指令首先在 v0.9.17版本中被介紹。

body_filter_by_lua_file

語法: body_filter_by_lua_file <path-to-lua-script-file>

上下文: http,server,location,location if

時期: output-body-filter

body_filter_by_lua等價坏匪,除了通過<path-to-lua-script-file>指定的文件包含Lua代碼拟逮,或者,從v0.5.0rc32版本開始适滓, Lua/LuaJIT bytecode被排除掉了敦迄。

當(dāng)給出了一個相對地址如 foo/bar.lua,他們會相對server prefix將其轉(zhuǎn)換為絕對地址,server prefix地址通過在啟動Nginx服務(wù)器時通過命令行里面的-p PATH指定罚屋。

這個指令在v0.5.0rc32版本中被首先介紹苦囱。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市脾猛,隨后出現(xiàn)的幾起案子撕彤,更是在濱河造成了極大的恐慌,老刑警劉巖猛拴,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件羹铅,死亡現(xiàn)場離奇詭異,居然都是意外死亡愉昆,警方通過查閱死者的電腦和手機(jī)职员,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來撼唾,“玉大人廉邑,你說我怎么就攤上這事〉构龋” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵糙箍,是天一觀的道長渤愁。 經(jīng)常有香客問我,道長深夯,這世上最難降的妖魔是什么抖格? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮咕晋,結(jié)果婚禮上雹拄,老公的妹妹穿的比我還像新娘。我一直安慰自己掌呜,他們只是感情好滓玖,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著质蕉,像睡著了一般势篡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上模暗,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天禁悠,我揣著相機(jī)與錄音,去河邊找鬼兑宇。 笑死碍侦,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瓷产,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼比规,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拦英?” 一聲冷哼從身側(cè)響起蜒什,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎疤估,沒想到半個月后灾常,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡铃拇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年钞瀑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片慷荔。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡雕什,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出显晶,到底是詐尸還是另有隱情贷岸,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布磷雇,位于F島的核電站偿警,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏唯笙。R本人自食惡果不足惜螟蒸,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望崩掘。 院中可真熱鬧七嫌,春花似錦、人聲如沸苞慢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枉疼。三九已至皮假,卻和暖如春澎怒,著一層夾襖步出監(jiān)牢的瞬間犬辰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工毛萌, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留航闺,地道東北人褪测。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓猴誊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親侮措。 傳聞我的和親對象是個殘疾皇子懈叹,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容