OpenResty获取参数的API

一、前言:OpenResty 提供了哪些"官方"参数获取 API?

很多初学者在 OpenResty 中获取请求参数时,要么记混方法,要么漏掉关键步骤(如未读 body),导致 nil 或空值。

其实,OpenResty(通过 ngx_lua 模块)提供了一套标准、高效的 API 来获取各类请求数据

掌握这些 API,你就能精准、安全、高效地提取所需信息。

本文将系统梳理所有核心 API,并附上使用示例与注意事项,助你一次写对!


二、核心 API 速览表

参数类型 API 方法 是否需预读 body 返回类型
请求方法 ngx.req.get_method() ❌ 否 string ("GET", "POST"...)
URI 路径 ngx.var.uri ❌ 否 string (/api/user)
GET 参数 ngx.req.get_uri_args() ❌ 否 table
请求头 ngx.req.get_headers() ❌ 否 table
POST 表单 ngx.req.get_post_args() ✅ 是 table
原始 Body ngx.req.get_body_data() ✅ 是 string / nil
Body 文件路径 ngx.req.get_body_file() ✅ 是 string / nil

🔑 黄金法则只要涉及请求体(body),必须先调用 ngx.req.read_body()


三、详细 API 使用指南

3.1 获取请求方法与 URI

Lua 复制代码
local method = ngx.req.get_method()  -- "GET", "POST", "PUT"...
local uri = ngx.var.uri              -- "/api/v1/user/123"

ngx.say("Method: ", method)
ngx.say("URI: ", uri)

💡 ngx.var.* 可访问所有 Nginx 内置变量(如 $remote_addr, $http_user_agent)。


3.2 获取 GET 参数(Query String)

Lua 复制代码
-- 请求: /search?q=openresty&page=2
local args = ngx.req.get_uri_args()

-- 安全访问
local q = args.q or ""
local page = tonumber(args.page) or 1

ngx.say("Search for: ", q, " on page ", page)

特点

  • 自动 URL 解码(%E4%B8%AD
  • 多值参数返回数组:?tag=a&tag=b{a, b}

3.3 获取请求头(Headers)

Lua 复制代码
local headers = ngx.req.get_headers()

-- 单个 Header(自动转小写)
local auth = headers.authorization  -- 注意是小写!
local ua = headers["user-agent"]

-- 遍历所有 Header
for name, value in pairs(headers) do
    ngx.log(ngx.INFO, "Header: ", name, " = ", tostring(value))
end

⚠️ 注意

  • Header 名自动转为小写
  • 多值 Header(如 Set-Cookie)返回 table

3.4 获取 POST 表单数据(x-www-form-urlencoded)

Lua 复制代码
-- 必须先读取 body!
ngx.req.read_body()

local post_args = ngx.req.get_post_args()

if not post_args then
    ngx.exit(400)
end

local username = post_args.username
local password = post_args.password

ngx.say("Login user: ", username or "unknown")

适用 Content-Typeapplication/x-www-form-urlencoded


3.5 获取原始请求体(Raw Body)

适用于 JSON、XML、Protobuf 等自定义格式。

Lua 复制代码
ngx.req.read_body()

-- 尝试从内存获取
local body = ngx.req.get_body_data()

-- 若 body 较大,会存入临时文件
if not body then
    local file_path = ngx.req.get_body_file()
    if file_path then
        local file = io.open(file_path, "r")
        body = file:read("*a")
        file:close()
    end
end

if body then
    ngx.say("Body length: ", #body)
else
    ngx.say("No body")
end

📌 触发文件存储的条件 :body 大小 > client_body_buffer_size(默认 8k~16k)


3.6 解析 JSON(配合 cjson)

虽然 cjson 不是 OpenResty 内置 API,但几乎必用:

Lua 复制代码
ngx.req.read_body()
local body = ngx.req.get_body_data()
if not body then ngx.exit(400) end

local cjson = require "cjson.safe"
local data, err = cjson.decode(body)

if not data then
    ngx.log(ngx.ERR, "JSON decode failed: ", err)
    ngx.exit(400)
end

ngx.say("User ID: ", data.userId)

强烈建议使用 cjson.safe,避免解析错误导致 worker 崩溃。


四、关键注意事项(避坑必看!)

⚠️ 1. ngx.req.read_body() 是阻塞操作

  • 会暂停当前请求直到 body 读完
  • 不要在高并发下处理超大文件(考虑流式读取)

⚠️ 2. get_post_args() 无法解析 JSON

  • 它只处理 key=value&key2=value2 格式
  • JSON 必须用 get_body_data() + cjson

⚠️ 3. 多值参数处理

Lua 复制代码
-- ?id=1&id=2
local ids = ngx.req.get_uri_args().id
if type(ids) == "table" then
    for _, id in ipairs(ids) do ... end
else
    -- 单值
end

⚠️ 4. 内存限制

  • 默认最大 body 为 client_max_body_size(通常 1M)
  • 超出会返回 413 错误

五、最佳实践:封装统一参数获取函数

Lua 复制代码
local _M = {}

function _M.get_all_params()
    local method = ngx.req.get_method()
    local params = {}

    if method == "GET" then
        params = ngx.req.get_uri_args()
    else
        ngx.req.read_body()
        local content_type = ngx.req.get_headers()["content-type"] or ""
        
        if content_type:find("application/json", 1, true) then
            local body = ngx.req.get_body_data()
            if body then
                local cjson = require "cjson.safe"
                params = cjson.decode(body) or {}
            end
        else
            params = ngx.req.get_post_args() or {}
        end
    end

    return params
end

return _M

在配置中使用:

Lua 复制代码
access_by_lua_block {
    local param_utils = require "param_utils"
    local params = param_utils.get_all_params()
    -- ...
}

六、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

相关推荐
難釋懷18 小时前
OpenResty请求参数处理
junit·openresty
難釋懷19 小时前
OpenResty获取参数并返回
junit·openresty
Boop_wu1 天前
[Java EE 进阶] Spring Boot 日志全面解析 : 配置与实战
junit·java-ee·单元测试
難釋懷4 天前
OpenResty快速入门
junit·openresty
FL4m3Y4n4 天前
Redis协议与异步方式
数据库·redis·junit
難釋懷5 天前
Lua语法入门-条件控制、函数
开发语言·junit·lua
難釋懷6 天前
Lua语法入门-变量和循环
开发语言·junit·lua
Java面试题总结6 天前
Junit到Springboot单元测试
spring boot·junit·单元测试
難釋懷6 天前
安装OpenResty
openresty