欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OpenResty文件上传upload

程序员文章站 2022-06-13 15:57:58
...

        对于OpenResty的使用,本章介绍一下文件上传。代码如下:

local upload = require "resty.upload"
local cjson = require "cjson"
local result = require "common.result"
local uuid = require 'resty.uuid'
local configCache = ngx.shared.configCache;

local _M = {}

-- 文件上传
function _M.file()
    local args = ngx.req.get_uri_args()
    local realFileName = uuid:generate()

    local chunk_size = 4096
    local form, err = upload:new(chunk_size)
    if not form then
        ngx.log(ngx.ERR, "failed to new upload: ", err)
        ngx.say(cjson.encode(result:error('failed to new upload')))
        return
    end

    form:set_timeout(1000)

    -- 字符串 split 分割
    string.split = function(s, p)
        local rt= {}
        string.gsub(s, '[^'..p..']+', function(w) table.insert(rt, w) end )
        return rt
    end

    -- 支持字符串前后 trim
    string.trim = function(s)
        return (s:gsub("^%s*(.-)%s*$", "%1"))
    end

    -- 保存根路径
    local saveRootPath = configCache:get('projectPath') .. "/images/"
    -- 文件对象
    local fileToSave
    -- 是否成功保存
    local ret_save = false

    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
            -- 读取header
            local key = res[1]
            local value = res[2]
            if key == "Content-Disposition" then
                -- 解析上传的文件名
                -- form-data; name="testFileName"; filename="testfile.txt"
                local kvlist = string.split(value, ';')
                for _, kv in ipairs(kvlist) do
                    local seg = string.trim(kv)
                    if seg:find("filename") then
                        local kvfile = string.split(seg, "=")
                        local filename = string.sub(kvfile[2], 2, -2)
                        if filename then
                            realFileName = realFileName .. '.' .. filename:match(".+%.(%w+)$")
                            fileToSave = io.open(saveRootPath .. realFileName, "w+")
                            if not fileToSave then
                                ngx.say("failed to open file ", filename)
                                return
                            end
                            break
                        end
                    end
                end
            end
        elseif typ == "body" then
            -- 读取 body
            if fileToSave then
                fileToSave:write(res)
            end
        elseif typ == "part_end" then
            -- 写结束 关闭文件
            if fileToSave then
                fileToSave:close()
                fileToSave = nil
            end
            
            ret_save = true
        elseif typ == "eof" then
            -- 读取结束
            break
        else
            -- do things
        end
    end

    ngx.say(cjson.encode(result:success("save file ok")))
end

return _M
        lua-resty-upload支持类型为multipart/form-data的MIME类型。当连接建立后,循环调用form:read()会返回4种http请求片断:header、body、part_end、eof。每次token返回的数据是一个数组,以header、body、part_end或者eof开头,如下所示:
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"]
        上述demo主要参见官方文档:https://github.com/openresty/lua-resty-upload
        还有一点需要注意的是,上面用到了lua-resty-uuid​​​​​​​对上传文件进行重命名(非OpenResty官方提供)。下载uuid.lua文件,直接粘贴到OpenResty安装目录lualib.resty文件夹下即可。

链接:http://moguhu.com/article/detail?articleId=19