Openresty + Lua 搭建文件服务器
目的
搭建静态文件服务器,用户访问浏览器地址下载相应的文件
如访问:http://127.0.0.1/doc/test.docx 即是下载test.docx文件
步骤
安装openresty
配置nginx.conf
#user nobody;
worker_processes 1;
events {
worker_connections 4096 ;
}
http {
include mime.types;
default_type application/octet-stream;
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
lua_package_path "lualib/?.lua;";
lua_package_cpath "lualib/?.so;";
resolver 114.114.114.114;
server {
listen 80;
server_name localhost;
# 文件存储路径
root C:/data/sharefile;
set $store_dir C:/data/sharefile/; # 文件存储路径
location / {
autoindex on; # 索引
autoindex_exact_size on; # 显示文件大小
autoindex_localtime on; # 显示文件时间
}
location /download {
alias C:/data/sharefile;
autoindex on;
index index.html index.htm;
}
location /upload {
client_max_body_size 4000m;
default_type application/json;
lua_code_cache on;
content_by_lua_file lua_scripts/upload.lua;
}
location /delete {
default_type application/json;
content_by_lua_file lua_scripts/deletefile.lua;
}
location /move{
default_type application/json;
content_by_lua_file lua_scripts/move.lua;
}
location /isexit{
default_type application/json;
content_by_lua_file lua_scripts/isexit.lua;
}
}
}
重新启动 openresty
访问 http://127.0.0.1,效果如下
配置
上传文件
-- upload.lua
--==========================================
-- 文件上传
--==========================================
local upload = require "resty.upload"
-- 文件保存的根路径
-- local saveRootPath = "/data/sharefile/"
local saveRootPath = ngx.var.store_dir
local baseurl = "download/"
local urllist = "{"
local dir = "0"
local newfilename
local acdd = "y" --[[自动创建目录]]
local arf = "y" --[[自动重命名文件]]
dir = ngx.req.get_uri_args()["dir"]
if dir == nil then
dir = "0"
end
local date_ym = os.date("%Y%m");
local date_d = os.date("%d");
acdd = ngx.req.get_uri_args()["acdd"]
if acdd == "n" then
saveRootPath = saveRootPath .. dir .. "/"
baseurl = baseurl .. dir .. "/"
else
saveRootPath = saveRootPath .. date_ym .. "/" .. date_d .. "/" .. dir .. "/"
baseurl = baseurl .. date_ym .. "/" .. date_d .. "/" .. dir .. "/"
end
arf = ngx.req.get_uri_args()["arf"]
local chunk_size = 40960
local form = upload:new(chunk_size)
if not form then
ngx.say("{\"error\":\"error\", \"msg\":\"no data post\"}")
return
end
-- 保存的文件对象
local file
--
function getFileName(res)
local filename = ngx.re.match(res, '(.+)filename="(.+)"(.*)')
if filename then
return filename[2]
end
end
--
function getExtension(str)
return str:match(".+%.(%w+)$")
end
--
function get16Md5(str)
return string.sub(str, 9, 24)
end
function getNewFileName(file_name)
if arf == "n" then
newfilename = file_name
return newfilename
else
local extension = getExtension(file_name)
local filedate = os.date("%y%m%d%H%M%S");
local md5 = get16Md5(ngx.md5(file_name));
if extension then
newfilename = filedate .. md5 .. "." .. extension
if not extension then
newfilename = filedate .. md5
end
end
return newfilename
end
end
function dir_exists(path)
local file = io.open(path, "rb")
if file then
--ngx.log(ngx.ERR, "path dir_exists************")
file:close()
end
if not file then
ngx.log(ngx.ERR, "path not dir_exists************")
-- linux系统
-- os.execute('mkdir -p ' .. path)
-- windows系统
local path1 = string.gsub(path, '/', '\\')
os.execute('md '.. path1)
end
end
--[[
local uritoken = ngx.req.get_uri_args()["token"]
local cookietoken = ngx.var.cookie_token --$cookie_token
local token = uritoken or cookietoken
if token == nil then
ngx.say("{\"error\":\"error\", \"msg\":\"token is empty\",url:\"\"}")
return
end
]]
while true do
--ngx.log(ngx.ERR, "1111************")
local typ, res, err = form:read()
--ngx.log(ngx.ERR, "2222-typ************"..typ)
if not typ then
ngx.say("{\"error\":\"error\", \"msg\":\"" .. tostring(err) .. "\"}")
return
end
if typ == "header" then
--[[
ngx.log(ngx.ERR, "3333-typ=header************"..type(res))
ngx.log(ngx.ERR, "RRRR-typ=header-res[1]************"..#(res))
for key, value in pairs(res) do
ngx.log(ngx.ERR, "KKK-typ=header-res[1] key************"..key)
ngx.log(ngx.ERR, "VVV-typ=header-res[1] value************"..value)
end
]]
--ngx.log(ngx.ERR, "4444-typ=header-res[1]************"..res[1])
if res[1] ~= "Content-Type" then
--ngx.log(ngx.ERR, "5555-res[2]************" .. res[2])
local file_name = getFileName(res[2])
if file_name then
getNewFileName(file_name)
dir_exists(saveRootPath)
local file_name_1 = saveRootPath .. newfilename
local fileexists = io.open(file_name_1, "rb")
if fileexists then
fileexists:close()
ngx.say("{\"error\":\"error\", \"msg\":\"[" .. newfilename .. "] file already exists\"}")
return
end
-- linux系统
-- file = io.open(file_name_1, "w+")
-- windows系统需要加b
file = io.open(file_name_1, "w+b")
urllist = urllist .. "\"" .. file_name .. "\":\"" .. baseurl .. newfilename .. "\","
if not file then
ngx.say("{\"error\":\"error\", \"msg\":\"failed to open file " .. file_name_1 .. "\"}")
return
end
end
end
elseif typ == "body" then
if file then
-- ngx.log(ngx.ERR, "9999-1111-write************"..res)
file:write(res)
end
elseif typ == "part_end" then
if file then
file:close()
end
file = nil
elseif typ == "eof" then
break
else
-- do nothing
end
end
local ul = string.sub(urllist, 1, -2)
local ull = ul .. "}"
--ngx.log(ngx.ERR, "ull************"..ull)
ngx.header["Content-Type"] = "application/json; charset=utf-8"
--ngx.header["Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept,filedir"
--ngx.header["filedir"] = ""
ngx.say("{\"error\":\"success\", \"msg\":\"success\",\"urllist\":" .. ull .. "}")
http://127.0.0.1/upload?dir=test&acdd=n&arf=n
参数 acdd
和 arf
可选
下载文件
download.lua
-- download.lua
--==========================================
-- 下载上传
--==========================================
local http = require "resty.http"
local upload = require "resty.upload"
local oss = require "resty.oss"
ngx.say("1231=================")
-- 获取上传的文件
function readFile()
local chunk_size = 4096
local form, err = upload:new(chunk_size)
form:set_timeout(20000)
local file = {}
if not err then
while true do
local typ, res, err2 = form:read()
if not typ then
err = err2
print("failed to read: ", err2)
break
end
if typ == 'header' and res[1] == 'Content-Disposition' then
local filename = string.match(res[2], 'filename="(.*)"')
file.name = filename
end
if typ == 'header' and res[1] == 'Content-Type' then
file['type'] = res[2]
end
if typ == 'body' and file then
file[typ] = (file[typ] or '') .. res
end
if typ == "eof" then
break
end
end
end
return file, err
end
local file, err = readFile()
local oss_config = {
accessKey = "xxxxxxxxxxxxxxxxxxxx",
secretKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
bucket = "xxxx",
endpoint = "oss-cn-beijing.aliyuncs.com"
}
local client = oss.new(oss_config)
local url = client:put_object(file.body, file.type, file.name)
ngx.say(url)
ngx.say("asdfasdfasdf2134123")
http://127.0.0.1/download/seal.jpg
移动文件
-- move.lua
--==========================================
-- 移动上传
--==========================================
local storepath = "/data/sharefile/"
local request_method = ngx.var.request_method
local sourcedir = ngx.req.get_uri_args()["sourceDir"]
local filename = ngx.req.get_uri_args()["fileName"]
local targetdir = ngx.req.get_uri_args()["targetDir"]
local romoveCmd = "mv".." "..storepath..sourcedir..filename.." "..storepath..targetdir..filename
local mv_file = os.execute(romoveCmd)
ngx.header["Content-Type"] = "application/json; charset=utf-8"
if(mv_file ~= 0) then
ngx.say("{\"error\":\"error\", \"msg\":\"move fail\"}")
else
ngx.say("{\"error\":\"success\", \"msg\":\""..targetdir..filename.."\"}")
end
删除文件
-- delete.lua
--==========================================
-- 删除上传
--==========================================
local storepath = "/data/sharefile/"
local request_method = ngx.var.request_method
local filename = ngx.req.get_uri_args()["f"]
local rm_file = os.remove(storepath..filename)
ngx.header["Content-Type"] = "application/json; charset=utf-8"
if(rm_file == nil) then
ngx.say("{\"error\":\"error\", \"msg\":\"file not exist or other reasons\"}")
else
ngx.say("{\"error\":\"success\", \"msg\":\"success\"}")
end