OpenResty 獲取請求 body

2021-08-12 17:31 更新

在 Nginx 的典型應(yīng)用場景中,幾乎都是只讀取 HTTP 頭即可,例如負載均衡、正反向代理等場景。但是對于 API Server 或者 Web Application ,對 body 可以說就比較敏感了。由于 OpenResty 基于 Nginx ,所以天然的對請求 body 的讀取細節(jié)與其他成熟 Web 框架有些不同。

最簡單的 “Hello ****”

我們先來構(gòu)造最簡單的一個請求,POST 一個名字給服務(wù)端,服務(wù)端應(yīng)答一個 “Hello ****”。

http {
    server {
        listen    80;

        location /test {
            content_by_lua_block {
                local data = ngx.req.get_body_data()
                ngx.say("hello ", data)
            }
        }
    }
}

測試結(jié)果:

?  ~  curl 127.0.0.1/test -d jack
hello nil

大家可以看到 data 部分獲取為空,如果你熟悉其他 web 開發(fā)框架,估計立刻就覺得 OpenResty 弱爆了。查閱一下官方 wiki 我們很快知道,原來我們還需要添加指令 lua_need_request_body 。究其原因,主要是 Nginx 誕生之初主要是為了解決負載均衡情況,而這種情況,是不需要讀取 body 就可以決定負載策略的,所以這個點對于 API Server 和 Web Application 開發(fā)的同學有點怪。

參看下面例子:

http {
    server {
        listen    80;

        # 默認讀取 body
        lua_need_request_body on;

        location /test {
            content_by_lua_block {
                local data = ngx.req.get_body_data()
                ngx.say("hello ", data)
            }
        }
    }
}

再次測試,符合我們預(yù)期:

?  ~  curl 127.0.0.1/test -d jack
hello jack

如果你只是某個接口需要讀取 body(并非全局行為),那么這時候也可以顯示調(diào)用 ngx.req.read_body() 接口,參看下面示例:

http {
    server {
        listen    80;

        location /test {
            content_by_lua_block {
                ngx.req.read_body()
                local data = ngx.req.get_body_data()
                ngx.say("hello ", data)
            }
        }
    }
}

body 偶爾讀取不到?

ngx.req.get_body_data() 讀請求體,會偶爾出現(xiàn)讀取不到直接返回 nil 的情況。

如果請求體尚未被讀取,請先調(diào)用 ngx.req.read_body (或打開 lua_need_request_body 選項強制本模塊讀取請求體,此方法不推薦)。

如果請求體已經(jīng)被存入臨時文件,請使用 ngx.req.get_body_file 函數(shù)代替。

如需要強制在內(nèi)存中保存請求體,請設(shè)置 client_body_buffer_size 和 client_max_body_size 為同樣大小。

參考下面代碼:

http {
    server {
        listen    80;

        # 強制請求 body 到臨時文件中(僅僅為了演示)
        client_body_in_file_only on;

        location /test {
            content_by_lua_block {
                function getFile(file_name)
                    local f = assert(io.open(file_name, 'r'))
                    local string = f:read("*all")
                    f:close()
                    return string
                end

                ngx.req.read_body()
                local data = ngx.req.get_body_data()
                if nil == data then
                    local file_name = ngx.req.get_body_file()
                    ngx.say(">> temp file: ", file_name)
                    if file_name then
                        data = getFile(file_name)
                    end
                end

                ngx.say("hello ", data)
            }
        }
    }
}

測試結(jié)果:

?  ~  curl 127.0.0.1/test -d jack
>> temp file: /Users/rain/Downloads/nginx/client_body_temp/0000000018
hello jack

由于 Nginx 是為了解決負載均衡場景誕生的,所以它默認是不讀取 body 的行為,會對 API Server 和 Web Application 場景造成一些影響。根據(jù)需要正確讀取、丟棄 body 對 OpenResty 開發(fā)是至關(guān)重要的。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號