一、前言: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-Type :application/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()
-- ...
}
六、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!