美文网首页
88.OpenResty实现文件的上传和下载

88.OpenResty实现文件的上传和下载

作者: 人生玩家Eli | 来源:发表于2022-11-09 22:39 被阅读0次
cover20220907.png
参考:使用openresty的lua-resty-upload实现文件上传
  1. 前几天在群里看到苏苏使用到了图床,以链接的形式发送图片,这样发到群里的图片就不担心失效了。
  2. 看到谢尔在群里发自我介绍,后面还放了一个飞书链接,里面有更详细的介绍。我在想把飞书链接换成图片链接是不是也挺好的?

图床,图床,图床...对了!Nginx!!!

突然想到了Nginx,我是不是可以做点什么,正好当练习了?

于是就打算用OpenResty搭个简易的图床,后来因为懒得判断文件类型等原因,就觉得不如实现一个网盘吧,先简单实现上传和下载功能就好。

配置

配置文件如下:

events{ # events块是必须要有的,不然会报错
}

http {
  server {
    listen 8081;
    root html;

    charset 'utf-8';
    autoindex on; # 启用目录浏览功能
    autoindex_exact_size off; # 显示文件大概的大小,并使用人类易读的单位

    location /upfile {
        client_max_body_size 2G; # 限制上传文件的大小,默认为1M
        content_by_lua_file lua/upload.lua;
    }

    # 当访问files文件夹中的文件时,修改header头
    # 这样在浏览器中点击文件就会进行下载,而不是打开
    location ~ ^/files/(.+)$ { 
      add_header Content-Disposition attachment;
      add_header Content-Type application/octet-stream;
    }
  }
}

前端界面及代码

简单实现了上传界面,如图:

前端界面1.png

代码如下:

<!--index.html-->
<html>
  <head>
    <meta charset="UTF-8">
    <title>文件上传</title>
  </head>
  <body>
    <form id="upload-form" action="upfile" method="post" enctype="multipart/form-data" >
     <input type="file" id="upload" name="upload" /> <br />
     <input type="submit" value="开始上传" />
    </form>
  </body>
</html>

文件浏览界面,点击文件可下载,如图:


前端界面1.png

后端代码

-- upload.lua
--==========================================
-- 文件上传
--==========================================
local upload = require "resty.upload"
local cjson = require "cjson"
local chunk_size = 4096
local form, err = upload:new(chunk_size)

if not form then
    ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
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 function get_file_name(header_value)
   local kvlist = string.split(header_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)
           return filename
       end
   end
end

-- 文件保存的根路径
local saveRootPath = "./html/files/";
-- 保存的文件对象
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 filename = get_file_name(value)
            if filename then
                local fullpath = saveRootPath .. filename
                if io.open(fullpath) then
                    ngx.say("文件已存在")
                    break
                end

                fileToSave = io.open(fullpath, "w+")
                if not fileToSave then
                    ngx.say("文件打开失败 ", filename)
                    break
                end
            end
        end
    elseif typ == "body" then
        -- 开始读取 http 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
        ngx.log(ngx.INFO, "do other things")
    end
end

if ret_save then
    ngx.say("上传文件成功。")
else
    ngx.say("上传文件失败。")
end

相关文章

网友评论

      本文标题:88.OpenResty实现文件的上传和下载

      本文链接:https://www.haomeiwen.com/subject/icnatdtx.html