Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> 電腦軟體教學 >> 伺服器技術 >> 關於伺服器

Nginx + Lua (OpenResty) 獲取 GET/POST 參數完整指南

編輯:關於伺服器

在基於 OpenResty (Nginx + ngx_lua) 的架構中,高效解析 HTTP 請求參數是核心需求。本文詳解從基礎 GET/POST 參數獲取到處理 multipart/form-data 文件上傳的進階 Lua 代碼實現,並分析關鍵 API 與邊界情況。

基礎版:區分 GET 與 POST 獲取參數

ngx_lua 提供原生 API 直接獲取解析後的參數表:

local request_method = ngx.var.request_method
local args

if request_method == "GET" then
    args = ngx.req.get_uri_args()
elseif request_method == "POST" then
    ngx.req.read_body()  -- 必須先讀取 body
    args = ngx.req.get_post_args()
end

local param1 = args["param1"]
local param2 = args["param2"]

關鍵點:POST 請求必須先調用 ngx.req.read_body() 將請求體讀入內存或臨時文件,否則 get_post_args() 返回空表。

進階版:支援 multipart/form-data 文件上傳解析

默認 get_post_args() 僅支援 application/x-www-form-urlencoded。若需處理文件上傳 (multipart/form-data),需手動解析請求體。以下為完整封裝函數:

local function parse_multipart_body()
    local headers = ngx.req.get_headers()
    local content_type = headers["content-type"]
    if not content_type or not content_type:find("multipart/form-data", 1, true) then
        return nil, "not multipart"
    end

    ngx.req.read_body()
    local body_data = ngx.req.get_body_data()
    -- 若 body 過大被寫入臨時文件,需從文件讀取
    if not body_data then
        local file_name = ngx.req.get_body_file()
        if not file_name then return nil, "no body file" end
        local fh, err = io.open(file_name, "rb")
        if not fh then return nil, "open file failed: " .. err end
        body_data = fh:read("*a")
        fh:close()
    end

    -- 提取 boundary
    local boundary = content_type:match("boundary=(.+)$")
    if not boundary then return nil, "no boundary" end
    boundary = "--" .. boundary

    -- 簡易分割解析 (生產環境建議使用 lua-resty-upload 庫)
    local parts = {}
    local start_pos = 1
    while true do
        local part_start = body_data:find(boundary, start_pos, true)
        if not part_start then break end
        local part_end = body_data:find(boundary, part_start + #boundary, true)
        if not part_end then break end
        local part = body_data:sub(part_start + #boundary + 2, part_end - 4) -- 去除 \r\n
        table.insert(parts, part)
        start_pos = part_end
    end

    local args, file_args = {}, {}
    for _, part in ipairs(parts) do
        local headers_block, value = part:match("^(.-)\r\n\r\n(.+)$")
        if headers_block and value then
            local name = headers_block:match('name="([^"]+)"')
            local filename = headers_block:match('filename="([^"]+)"')
            if name then
                if filename then
                    file_args[name] = { filename = filename, content = value }
                else
                    args[name] = value
                end
            end
        end
    end
    return args, file_args
end

-- 使用示例
local get_args = ngx.req.get_uri_args()
local post_args, files = parse_multipart_body()
local all_args = post_args or get_args

生產環境建議:使用成熟庫

手寫解析器易出錯且效能不佳。強烈建議使用 OpenResty 生態的成熟庫:

  • lua-resty-upload:流式處理大文件上傳,不佔用大量內存。
    local upload = require "resty.upload"
  • lua-resty-reqargs:統一獲取 GET/POST/JSON 參數,自動處理 Content-Type。
    local reqargs = require "resty.reqargs"

效能與安全注意事項

  1. client_body_buffer_size:默認 8k/16k,超過則寫入磁臨時文件,增加 I/O 開銷。大文件上傳場景需調大或使用流式處理。
  2. client_max_body_size:限制最大請求體大小,防止惡意佔用磁碟空間。
  3. 輸入驗證:所有外部參數務必進行類型、長度、格式驗證,防止注入攻擊。
  4. 緩存參數表:同一請求多次獲取參數時,建議存入 ngx.ctx 避免重複解析。

掌握 Nginx+Lua 參數處理機制,能構建高效能、靈活的 API 網關與 Web 應用防火牆 (WAF) 邏輯。

Copyright © Windows教程網 All Rights Reserved