在 OpenResty 中处理 multipart/form-data
上传文件并写入磁盘,可以通过以下两种方式实现:
1. 使用现成的 Lua 库:lua-resty-upload
这是 OpenResty 官方推荐的库,用于解析上传的文件流。虽然它不直接提供文件保存功能,但可以结合 Lua 的文件操作 API 实现。
示例代码:
local upload = require "resty.upload"
local chunk_size = 4096 -- 分块大小
-- 初始化上传解析器
local form, err = upload:new(chunk_size)
if not form then
ngx.log(ngx.ERR, "failed to new upload: ", err)
return ngx.exit(500)
end
-- 指定保存路径
local file_path = "/tmp/uploaded_file.txt"
local file, err = io.open(file_path, "w+")
if not file then
ngx.log(ngx.ERR, "failed to open file: ", err)
return ngx.exit(500)
end
-- 逐块读取并写入文件
while true do
local typ, res, err = form:read()
if not typ then
ngx.log(ngx.ERR, "failed to read: ", err)
break
end
if typ == "body" then
-- 写入文件块
file:write(res)
elseif typ == "part_end" then
-- 单个文件部分结束
file:close()
break
end
-- 其他类型(如 header)忽略处理
end
ngx.say("File saved to: ", file_path)
2. 使用第三方增强库:lua-resty-multipart
如果需要更高级的功能(如自动文件名处理、内存优化),可以使用社区维护的 lua-resty-multipart。
安装:
通过 opm
安装:
opm get Kong/lua-resty-multipart
示例代码:
local multipart = require "resty.multipart"
local filename = "uploaded_file.txt"
local path = "/tmp/" .. filename
-- 解析请求体
local mp_data, err = multipart(ngx.req.get_body_data(), ngx.req.get_headers()["Content-Type"])
if not mp_data then
ngx.log(ngx.ERR, "parse failed: ", err)
return ngx.exit(400)
end
-- 获取文件数据并保存到磁盘
for part in mp_data:parts() do
if part.filename then
local file_content = part.data
local fh, err = io.open(path, "wb")
if fh then
fh:write(file_content)
fh:close()
ngx.say("File saved as ", path)
else
ngx.log(ngx.ERR, "Failed to save file:", err)
end
break --假设只处理第一个文件
end
end
关键注意事项
性能与安全:
- 大文件需分块处理(避免内存爆炸)。
- 检查文件名和路径合法性,防止目录遍历攻击(如
../
)。 - 限制上传文件大小(通过
client_max_body_size
)。
OpenResty配置: “`nginx.confhttp { server {
location /upload { content_by_lua_file /path/to/your_upload_script.lua; client_max_body_size100M; #允许最大100MB上传 }
} } “`
替代方案:
- Nginx原生模块:
nginx-upload-module
(需重新编译Nginx)。
- Nginx原生模块:
如果需要进一步优化或扩展功能,可以基于上述库封装自己的逻辑。
内容由零声教学AI助手提供,问题来源于学员提问