lua-resty-upload
基于 ngx_lua cosocket 的 HTTP 文件上传流读取器和解析器
$ opm get openresty/lua-resty-upload
名称
lua-resty-upload - 基于 ngx_lua cosocket 的 HTTP 文件上传流读取器和解析器
状态
该库被认为是生产就绪的。
描述
该 Lua 库是 ngx_lua nginx 模块的流文件上传 API
http://wiki.nginx.org/HttpLuaModule
支持 multipart/form-data MIME 类型。
该库的 API 只返回一个一个的令牌。用户只需要重复调用 read
方法,直到返回 nil 令牌类型。对于从 read
方法返回的每个令牌,只需检查第一个返回值以获取当前令牌类型。令牌类型可以是 header
、body
和 part end
。每个解析的 multipart/form-data
表单字段包含多个 header
令牌,每个令牌都包含一个字段头,多个 body
令牌,每个令牌都包含一个主体数据块,以及一个 part end
标志,指示字段结束。
这就是流式读取的工作原理。即使对于千兆字节的文件数据输入,lua 领域的内存使用量也可以保持较小且恒定,只要用户自己不累积输入数据块。
该 Lua 库利用了 ngx_lua 的 cosocket API,从而确保了 100% 的非阻塞行为。
请注意,至少需要 ngx_lua 0.7.9 或 OpenResty 1.2.4.14。
概要
lua_package_path "/path/to/lua-resty-upload/lib/?.lua;;";
server {
location /test {
content_by_lua '
local upload = require "resty.upload"
local cjson = require "cjson"
local chunk_size = 5 -- should be set to 4096 or 8192
-- for real-world settings
local form, err = upload:new(chunk_size)
if not form then
ngx.log(ngx.ERR, "failed to new upload: ", err)
ngx.exit(500)
end
form:set_timeout(1000) -- 1 sec
while true do
local typ, res, err = form:read()
if not typ then
ngx.say("failed to read: ", err)
return
end
ngx.say("read: ", cjson.encode({typ, res}))
if typ == "eof" then
break
end
end
local typ, res, err = form:read()
ngx.say("read: ", cjson.encode({typ, res}))
';
}
}
上面定义的 /test 位置的典型输出是
read: ["header",["Content-Disposition","form-data; name=\"file1\"; filename=\"a.txt\"","Content-Disposition: form-data; name=\"file1\"; filename=\"a.txt\""]]
read: ["header",["Content-Type","text\/plain","Content-Type: text\/plain"]]
read: ["body","Hello"]
read: ["body",", wor"]
read: ["body","ld"]
read: ["part_end"]
read: ["header",["Content-Disposition","form-data; name=\"test\"","Content-Disposition: form-data; name=\"test\""]]
read: ["body","value"]
read: ["body","\r\n"]
read: ["part_end"]
read: ["eof"]
read: ["eof"]
您可以使用 lua-resty-string 库来增量计算文件数据的 SHA-1 和 MD5 摘要。以下是一个这样的示例
local resty_sha1 = require "resty.sha1"
local upload = require "resty.upload"
local chunk_size = 4096
local form = upload:new(chunk_size)
local sha1 = resty_sha1:new()
local file
while true do
local typ, res, err = form:read()
if not typ then
ngx.say("failed to read: ", err)
return
end
if typ == "header" then
local file_name = my_get_file_name(res)
if file_name then
file = io.open(file_name, "w+")
if not file then
ngx.say("failed to open file ", file_name)
return
end
end
elseif typ == "body" then
if file then
file:write(res)
sha1:update(res)
end
elseif typ == "part_end" then
file:close()
file = nil
local sha1_sum = sha1:final()
sha1:reset()
my_save_sha1_sum(sha1_sum)
elseif typ == "eof" then
break
else
-- do nothing
end
end
如果您想为上传的文件计算 MD5 校验和,只需使用 lua-resty-string 库提供的 resty.md5 模块即可。它具有与 resty.sha1 相似的 API。
对于大型文件上传,重要的是不要将所有数据缓冲在内存中。也就是说,您永远不应该在巨大的 Lua 字符串或巨大的 Lua 表中累积数据块。您必须尽快将数据块写入文件,并立即丢弃数据块(以便让 Lua GC 释放它)。
除了将数据块写入文件(如上面的示例所示)之外,您还可以将数据块写入上游 cosocket 连接,如果您不想在本地文件系统上保存数据。
作者
Yichun "agentzh" Zhang (章亦春) <[email protected]>,OpenResty Inc.
版权和许可
该模块是在 BSD 许可下授权的。
版权所有 (C) 2012-2017,由 Yichun "agentzh" Zhang (章亦春) <[email protected]>,OpenResty Inc.
保留所有权利。
在满足以下条件的情况下,允许以源代码和二进制形式重新分发和使用本软件,无论是否修改:
源代码的重新分发必须保留上述版权声明、本条件列表和以下免责声明。
二进制形式的重新分发必须在随分发提供的文档和/或其他材料中复制上述版权声明、本条件列表和以下免责声明。
本软件由版权持有人和贡献者“按现状”提供,并且任何明示或暗示的担保,包括但不限于适销性和特定用途适用性的暗示担保,均被免除。在任何情况下,版权持有人或贡献者均不对任何直接、间接、偶然、特殊、惩罚性或后果性损害(包括但不限于替代商品或服务的采购;使用、数据或利润损失;或业务中断)负责,无论其原因是什么,以及任何责任理论,无论是合同、严格责任还是侵权(包括疏忽或其他原因),均因使用本软件而产生,即使已被告知可能发生此类损害。
另请参阅
作者
Yichun "agentzh" Zhang (agentzh)
许可
2bsd
版本
-
基于 ngx_lua cosocket 的 HTTP 文件上传流读取器和解析器 2018-06-05 18:16:17
-
基于 ngx_lua cosocket 的 HTTP 文件上传流读取器和解析器 2016-09-29 03:22:50