[code.openresty] Openresty Nginx API for Lua -下

ngx.req.socket

語法: tcpsock, err = ngx.req.socket()

語法: tcpsock, err = ngx.req.socket(raw)

上下文: rewrite_by_lua*, access_by_lua*, content_by_lua*

返回一個包含了下游連接的只讀的cosocket對象。在這個對象里面,只支持receivereceiveuntil方法。

在發(fā)生錯誤的情況下,將會返回一個nil值和一個描述錯誤的字符串。

這個方法返回的socket對象經(jīng)常被用來讀取請求的body,以一個流的方式。不要開啟lua_need_request_body指令,并且不要將這個調(diào)用與ngx.req.read_bodyngx.req.discard_body混合使用。

如果任何請求的body數(shù)據(jù)已經(jīng)被預(yù)讀到Nginx內(nèi)核請求header緩沖區(qū)中,結(jié)果cosocket對象要小心的處理這些來避免這種預(yù)讀取中潛在的數(shù)據(jù)丟失。分塊請求的body在這個API中不支持。

v0.9.0版本開始,這個方法接受一個可選的 boolean raw參數(shù)。當(dāng)這個參數(shù)是true,這個方法返回一個全雙工的cosocket對象包裝原始的下游連接套接字,在這里你可以調(diào)用receive, receiveuntil, 和 send方法。

當(dāng)raw參數(shù)是true,要求這里沒有從之前ngx.say, ngx.print, 或者 ngx.send_headers 調(diào)用時未解決的數(shù)據(jù)存在。所以,如果你之前有這些下游輸出調(diào)用,你應(yīng)該在調(diào)用ngx.req.socket(true)之前調(diào)用ngx.flush(true)來保證這里沒有未解決的輸出數(shù)據(jù)。如果請求body還沒有被讀取,那么"raw socket"也可以被用來讀取請求的body。

你可以使用通過ngx.req.socket(true)返回的“raw request socket”來實現(xiàn)花哨的協(xié)議例如WebSocket,或者只是發(fā)出你自己的未加工的HTTP響應(yīng)頭或者body數(shù)據(jù)。你可以參考lua-resty-websocket library的一個真實世界的例子。

這個方法首先從v0.5.0rc1版本被介紹。

ngx.exec

語法: ngx.exec(uri,args?)

上下文: rewrite_by_lua*, access_by_lua*, content_by_lua*

做一個內(nèi)部重定向到uri附帶參數(shù)arg并且和echo-nginx-module中的echo_exec相似。


  ngx.exec('/some-location');
  ngx.exec('/some-location', 'a=3&b=5&c=6');
  ngx.exec('/some-location?a=3&b=5', 'c=6');

這個可選的第二個參數(shù)args可以被用來指定額外的URI查詢參數(shù),例如:


  ngx.exec("/foo", "a=3&b=hello%20world")

作為另一種選擇,一個Lua table中可以被當(dāng)做args參數(shù)傳遞,ngx_lua來展開URI轉(zhuǎn)義和字符串連接。


  ngx.exec("/foo",{ a = 3, b = "hello world" })

這個結(jié)果和之前的例子是完全相同的。

通過Lua table傳遞args參數(shù)的形式和通過使用ngx.encode_args方法是完全一樣的。

同樣也支持命名的location但是第二個args參數(shù)將會被忽略掉,如果查詢字符串存在并且新location會繼承自以前的location(如果有的話)。

在下面的例子中,GET /foo/file.php?a=hello將會返回“hello”而不是“goodbye”。


      location /foo {
          content_by_lua_block {
              ngx.exec("@bar","a=goodbye");
          }
      }

      location @bar {
          content_by_lua_block {
              local args = ngx.req.get_uri_args()
              for key, val in pairs(args) do
                    if key == "a" then
                        ngx.say(val)
                    end
              end
          }
      }

注意ngx.exec方法和ngx.redirect并不一樣,這是由于它是一個純粹的外部重定向并且不包括額外的HTTP流量。

并且注意這個方法調(diào)用終止當(dāng)前請求的處理并且它 必須ngx.send_headers或者ngx.printngx.say明確響應(yīng)body輸出之前調(diào)用。

建議編碼時候,將這個方法調(diào)用和return語句結(jié)合,例如:return ngx.exec(...)可以在除了header_filter_by_lua*之外的上下文中使用,以強調(diào)程序已經(jīng)被終止的事實。

ngx.redirect

語法: ngx.redirect(uri, status?)

上下文: rewrite_by_lua*, access_by_lua*, content_by_lua*

發(fā)出一個HTTP 301或者302重定向到uri。

這個可選的status參數(shù)指定要使用的HTTP狀態(tài)?,F(xiàn)在支持下面的狀態(tài)碼:

  • 301
  • 302 (默認(rèn))
  • 303
  • 307

默認(rèn)的是 302 (ngx.HTTP_MOVED_TEMPORARILY)

這里有一個例子,假設(shè)當(dāng)前的服務(wù)器名稱是localhost,并且監(jiān)聽的端口是 1984:


    return ngx.redirect("/foo")

等價于


 return ngx.redirect("/foo", ngx.HTTP_MOVED_TEMPORARILY)

支持重定向任意外部的URL,例如:


  return ngx.redirect("http://www.google.com")

我們也可以直接使用數(shù)值代碼作為第二個status參數(shù):


  return ngx.redirect("/foo",301)

這個方法和標(biāo)準(zhǔn)ngx_http_rewrite_module中的附帶redirect修飾符的rewrite 指令類似,例如,這個nginx.conf片段


  rewrite ^ /foo? redirect; # nginx config

等價于下面的Lua代碼


  return ngx.redirect('/foo'); -- Lua code


  rewrite ^ foo? permanent; #nginx config

等價于


  return ngx.redirect('/foo',ngx.HTTP_MOVED_PERMANENTLY)  -- Lua code

也可以指定URI參數(shù),例如:


 return ngx.redirect('/foo?a=3&b=4')

注意這個方法調(diào)用終止當(dāng)前請求的運行并且它 必須ngx.send_headers調(diào)用或者通過ngx.print或者 ngx.say明確響應(yīng)body輸出之前。

建議的編碼風(fēng)格是,將這個方法調(diào)用與一個return聲明結(jié)合,例如,return ngx.redirect(...)在除了header_filter_by_lua*之外的上下文中被接受,來強調(diào)一個事實就是這個請求處理已經(jīng)被終止了。

ngx.send_headers

語法: ok, err = ngx.send_headers()

上下文: rewrite_by_lua*,access_by_lua*,content_by_lua*

顯示的發(fā)送出響應(yīng)頭。

v0.8.3版本這個方法在成功的時候返回1,在其他情況下返回一個nil和一個字符串描述錯誤。

注意通常情況下不需要手動發(fā)送出響應(yīng)頭,因為ngx_lua會在內(nèi)容通過 ngx.say 或者 ngx.print輸出之前自動的將響應(yīng)頭發(fā)出,或者當(dāng)content_by_lua*正常退出時。

ngx.headers_sent

語法: value = ngx.headers_sent

上下文: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*

如果響應(yīng)頭被發(fā)出去了(通過ngx_lua)將會返回true,其他情況返回false。

這個API首先在ngx_lua v0.3.1rc6版本中被介紹。

ngx.print

語法: ok,err = ngx.print(...)

上下文: rewrite_by_lua*, access_by_lua*, content_by_lua*

發(fā)出已經(jīng)連接過的參數(shù)到HTTP客戶端(作為響應(yīng)body)。如果響應(yīng)頭沒有被發(fā)送,這個方法將會首先發(fā)出headers然后發(fā)出body數(shù)據(jù)。

v0.8.3,這個方法在成功后返回1,在其他情況下返回nil和一個描述錯誤信息的字符串。

Lua nil值將會輸出"nil"字符串并且Lua boolean值將會分別輸出"true""false"文字字符串。

嵌套的字符串是數(shù)組是允許的并且數(shù)組中的元素將會被一個接著一個的輸出:


 local table = {
     "hello, ",
     {"world: ", true, " or ", false,
         {": ", nil}}
 }
 ngx.print(table)

將會產(chǎn)生輸出:


 hello, world: true or false: nil

非數(shù)組的表參數(shù)將會導(dǎo)致拋出一個Lua異常。

這個ngx.null常量將會產(chǎn)生"null"字符串輸出。

這是一個異步的調(diào)用并且將會立即返回而不需要等待所有的數(shù)據(jù)要寫入系統(tǒng)發(fā)送緩存區(qū)中。要開啟同步模式,在調(diào)用ngx.print之后調(diào)用ngx.flush(true)。這個對流輸出特別有用。更多細(xì)節(jié)查看ngx.flush。

請注意一點ngx.printngx.say會總是調(diào)用整個Nginx輸出body過濾鏈,這個是一個昂貴的操作。所以在一個緊密循環(huán)中無論調(diào)用哪一個都要小心。你自己在Lua中緩沖數(shù)據(jù)并且保存調(diào)用。

ngx.say

語法: ok, err = ngx.say(...)

上下文: rewrite_by_lua*, access_by_lua*, content_by_lua*

ngx.print類似但是多發(fā)出一個換行符。

ngx.log

語法: ngx.log(log_level, ...)

上下文: init_by_lua*, 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_session_fetch_by_lua*, ssl_session_store_by_lua*

通過給定的logging級別來連接參數(shù)到error.log中。

Lua nil參數(shù)是接受的,并且結(jié)果為文字的"nil"字符串,同時Lua boolean結(jié)果為文字的"true"或者"false"字符串輸出。并且ngx.null常量將會產(chǎn)生"null"字符串輸出。

這個log_level參數(shù)可以取常數(shù)例如ngx.ERRngx.WARN.檢查Nginx log level constants來獲取細(xì)節(jié)。

這里有個Nginx內(nèi)核硬編碼的2048字節(jié)的限制在錯誤信息長度上。這個限制包含結(jié)尾換行開頭的時間戳。如果信息大小超過了這個限制,Nginx會相應(yīng)的截取信息字符串。這個限制可以通過編輯在Nginx源碼樹種的src/core/ngx_log.h 文件的NGX_MAX_ERROR_STR宏定義來修改。

ngx.flush

語法: ok, err = ngx.flush(wait?)

上下文: rewrite_by_lua*, access_by_lua*, content_by_lua*

Flush 響應(yīng)輸出到客戶端。

ngx.flush接受一個可選的boolean wait參數(shù)(默認(rèn):false),首先在v0.3.1rc34版本中介紹。當(dāng)通過默認(rèn)的參數(shù)調(diào)用的時候,它纏身給一個異步的調(diào)用(立即返回而不等待輸出數(shù)據(jù)被寫入到系統(tǒng)的發(fā)送緩沖中)。通過wait參數(shù)設(shè)置為true調(diào)用這個方法會轉(zhuǎn)變?yōu)橥侥J健?/p>

在同步模式,這個方法將會不會返回直到所有的輸出數(shù)據(jù)已經(jīng)被寫入到系統(tǒng)輸出緩沖中或者直到send_timeout設(shè)置已經(jīng)過期了。注意使用Lua協(xié)同程序機(jī)制意味著這個方法并不阻塞Nginx事件循環(huán)及時在同步模式。

當(dāng)ngx.flush(true)ngx.print或者ngx.say之后被立即調(diào)用,這回導(dǎo)致后者的方法在同步模式下運行。這個在流輸出中特別有用。

注意ngx.flush在HTTP 1.0輸出緩沖模式中并不是一個功能。查看HTTP 1.0 support。

v0.8.3開始這個方法在成功之后返回1,在其他情況下返回nil和一個字符串來描述錯誤。

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*, ssl_session_store_by_lua*

當(dāng)status >= 200 (例如,ngx.HTTP_OK和以上),它將會中斷當(dāng)前的請求并且返回狀態(tài)碼給nginx。

當(dāng)status == 0 (例如,ngx.OK),它將會退出當(dāng)前的階段處理器(或者內(nèi)容處理器如果 content_by_lua*指令被使用了)并且為當(dāng)前請求繼續(xù)運行后面的階段(如果有的話)。

這個status參數(shù)可以使ngx.OK, ngx.ERROR,ngx.HTTP_NOT_FOUND,ngx.HTTP_MOVED_TEMPORARILY,或者其他 HTTP status constants。

要返回一個包含當(dāng)前內(nèi)容的錯誤頁,可以使用像這樣的代碼片段:


 ngx.status = ngx.HTTP_GONE
 ngx.say("This is our own content")
 -- to cause quit the whole request rather than the current phase handler
 ngx.exit(ngx.HTTP_OK)

執(zhí)行的效果:


 $ curl -i http://localhost/test
 HTTP/1.1 410 Gone
 Server: nginx/1.0.6
 Date: Thu, 15 Sep 2011 00:51:48 GMT
 Content-Type: text/plain
 Transfer-Encoding: chunked
 Connection: keep-alive

 This is our own content

數(shù)值文本可以直接被用在參數(shù)上,例如,


 ngx.exit(501)

注意盡管這個方法接受所有的 HTTP status constants作為輸入,它只接受core constants中的NGX_OKNGX_ERROR

還要注意,這個方法調(diào)用歐冠終止當(dāng)前請求的處理并且建議的編碼風(fēng)格是將這個方法調(diào)用歐冠與一個return聲明連接,例如, return ngx.exit(...)被用來強調(diào)一個事實是請求處理已經(jīng)被終止了。

當(dāng)用在header_filter_by_lua*, balancer_by_lua*, 和
ssl_session_store_by_lua*的上下中時,ngx.exit()作為一個異步的操作將會立即返回。這個行為在未來可能會改變并且推薦用戶使用上面推薦的return來結(jié)合使用。

ngx.eof

語法: ok, err = ngx.eof()

上下文: rewrite_by_lua*, access_by_lua*, content_by_lua*

顯示的指定響應(yīng)輸出流的結(jié)束。在HTTP 1.1分塊編碼輸出的情況下,它將只是會觸發(fā)Nginx內(nèi)核發(fā)送出"last chunk"。

當(dāng)你在你下游連接中禁用了HTTP 1.1的keep-alive特性時,你可以調(diào)用這個方法來寫到HTTP client來主動的關(guān)閉連接。這個技巧可以用在做一些后臺工作而不讓HTTP客戶端等待連接,例如下面的例子:


 location = /async {
     keepalive_timeout 0;
     content_by_lua_block {
         ngx.say("got the task!")
         ngx.eof()  -- well written HTTP clients will close the connection at this point
         -- access MySQL, PostgreSQL, Redis, Memcached, and etc here...
     }
 }

但是如果你創(chuàng)建子請求來訪問其他通過nginx upstream模塊配置的location,那么你應(yīng)該配置這些upstream模塊來忽略客戶端連接中斷,如果他們不是默認(rèn)情況的話。例如,在默認(rèn)情況下標(biāo)準(zhǔn)的ngx_http_proxy_module將會同時中斷子請求和主請求,當(dāng)客戶端重點連接時,所以在你的location塊ngx_http_proxy_module配置中開啟proxy_ignore_client_abort](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_client_abort) 指令是非常重要的。


 proxy_ignore_client_abort on;

一個更好的來做后臺工作的方式是使用ngx.timer.atAPI接口。

v0.8.3開始這個方法在成功時候返回1,在其他錯誤情況下返回nil和一個字符串描述。

ngx.sleep

語法: ngx.sleep(seconds)

上下文: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*

睡眠指定的描述而不阻塞。可以指定一個時間分辨率達(dá)到0.001秒(例如:一毫秒)。

在后面的場景,這個方法使用的是Nginx timers。

0.7.20版本開始,這個0時間參數(shù)也可以被指定。

這個方法首先在0.5.0rc30版本中被介紹。

ngx.escape_uri

語法: newstr = ngx.escape_uri(str)

上下文: init_by_lua*, 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_session_fetch_by_lua*, ssl_session_store_by_lua*

編碼str來作為URI組件。

ngx.unescape_uri

語法: newstr = ngx.unescape_uri(str)

上下文: init_by_lua*, 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*

解碼str,str是一個編碼過的URI組件。

例如:


 ngx.say(ngx.unescape_uri("b%20r56+7"))

得到輸出


    b r56 7

ngx.encode_args

語法: str = ngx.encode_args(table)

上下文: 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*

根據(jù)URI的編碼規(guī)則編碼Lua table為一個查詢參數(shù)字符串。

例如,


 ngx.encode_args({foo = 3, ["b r"] = "hello world"})

產(chǎn)生


foo=3&b%20r=hello%20world

這個table的keys必須是Lua字符串。

同時也支持多值查詢參數(shù)。使用一個lua table來作為參數(shù)值,例如:


 ngx.encode_args({baz = {32, "hello"}})

得到


    baz=32&baz=hello

如果這個value table為空那么影響等價于nil值。

同時也支持boolean參數(shù)值,例如,


 ngx.encode_args({a = true, b = 1})

產(chǎn)生


    a&b=1

如果這個參數(shù)值為false,那么影響等價于nil值。

這個方法首先在 v0.3.1rc27版本中被介紹。

ngx.decode_args

語法: table = ngx.decode_args(str, max_args?)

上下文: 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_session_fetch_by_lua*, ssl_session_store_by_lua*

將一個編碼過的查詢字符串解碼為一個Lua table。這個是ngx.encode_args的相反的方法。

這個可選的max_args參數(shù)可以被用來指定通過str參數(shù)解析的參數(shù)數(shù)量的最大值。默認(rèn)情況下,默認(rèn)解析100個請求參數(shù)(包括這些名字相同的)并且額外的URI參數(shù)會被默默的丟棄來防止?jié)撛诘木芙^服務(wù)攻擊。

這個參數(shù)可以被設(shè)置為0來移除對接受請求參數(shù)處理的限制:


 local args = ngx.decode_args(str, 0)

強烈不建議移除max_args。

這個方法首先在v0.5.0rc29版本中被介紹。

encode_base64

語法: newstr = ngx.encode_base64(str, no_padding?)

上下文: 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_session_fetch_by_lua*, ssl_session_store_by_lua*

編碼str成為一個base64摘要。

0.9.16版本開始,一個可選的boolean類型no_padding參數(shù)可以被指定來控制是否base64摘要應(yīng)該被追加到結(jié)果摘要中(默認(rèn)是false,例如,使用啟用追加)。

ngx.decode_base64

語法: newstr = ngx.decode_base64(str)

上下文: 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_session_fetch_by_lua*, ssl_session_store_by_lua*

解碼str參數(shù)將base64摘要成為一個原始的形式。如果str不是正常形式返回nil。

ngx.crc32_short

語法: intval = ngx.crc32_short(str)

上下文: 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_session_fetch_by_lua*, ssl_session_store_by_lua*

計算str字符串的CRC-32(循環(huán)冗余碼)摘要。

這個方法對較短的str輸入(例如,小于30~60bytes)表現(xiàn)較好,和ngx.crc32_long相比。這個結(jié)果和ngx.crc32_long完全一樣。

幕后的實現(xiàn),這個只是一個薄薄的對Nginx核心中的ngx_crc32_short的封裝。

這個API首先在v0.3.1rc8版本中被介紹。

ngx.crc32_long

語法: intval = ngx.crc32_long(str)

上下文: 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_session_fetch_by_lua*, ssl_session_store_by_lua*

計算參數(shù)strHMAC-SHA1摘要,并且返回使用密鑰<secret_key>的結(jié)果。

原始字節(jié)形式的HMAC-SHA1證書將會生成,使用ngx.encode_base64,例如,如果需要的話將結(jié)果以結(jié)果的文本表示。

例如,


 local key = "thisisverysecretstuff"
 local src = "some string we want to sign"
 local digest = ngx.hmac_sha1(key, src)
 ngx.say(ngx.encode_base64(digest))

將會導(dǎo)致輸出:


    R/pvxzHC4NLtj7S+kXFg/NePTmk=

這個API需要在Nginx編譯的時候開啟OpenSSL庫(通常在./configure腳本里面?zhèn)魅?code>--with-http_ssl_module參數(shù))

這個方法首先在v0.3.1rc29版本中被介紹。

ngx.md5

語法: ngx.md5(str)

上下文: 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_session_fetch_by_lua*, ssl_session_store_by_lua*

返回str參數(shù)的16進(jìn)制的MD5摘要。

例如,


 location = /md5 {
     content_by_lua_block { ngx.say(ngx.md5("hello")) }
 }

產(chǎn)生輸出


    5d41402abc4b2a76b9719d911017c592

查看ngx.md5_bin,如果需要原始的MD5摘要。

ngx.sha1_bin

語法: digest = ngx.sha1_bin(str)

上下文: 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_session_fetch_by_lua*, ssl_session_store_by_lua*

返回str參數(shù)的二級制形式的SHA-1摘要。

這個方法需要在Nginx編譯時的SHA-1支持。(這個經(jīng)常意味著在構(gòu)建Nginx時需要安裝OpenSSL)

這個方法首先在v0.5.0rc6中被介紹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容