一、需求说明
前端经常需要增加一些模板jpg,然后重新发到生产;因此增加了一个功能,让用户自己上传模板jpg到前端服务器上。 前端项目位于前端服务器,有nginx;为了实现功能,再装一个jdk+java后台代码实现感觉不太合适,因此使用nginx+lua实现文件上传功能。
二、具体流程
1.访问前端服务器,例如http://10.123.123.123 ,此时出现的是nginx的欢迎页面,如果是Welcome to OpenResty ,说明安装的是resty(这个软件包含nginx功能),那么环境基本是可以的;如果安装的是普通的nginx,那么可能需要重装为openresty。
2.修改resty(nginx)的配置信息,例如/home/appadmin/nginx/conf/nginx.conf ,增加一个上传文件用的路径,样例如下:
location /uploadFile {
error_log logs/upload.err.log;
#if ($remote_addr !~* "^10\.13(0|3)\.(.*)\.(.*)$") { echo "ip wrong!"; }
#set $home_path "/home/appadmin/uploadFile";
#set $sub_path $head_sub_path;
#lua_code_cache off;
content_by_lua_file conf/luascript/upfile.lua;
}
说明: (1)注释的home_path的意思是,可以把文件上传后保存的路径配置在这里,后续lua文件取这里的值即可。 (2)注释的sub_path的意思是,可以从请求头head_sub_path中读取一个路径(前端设置的),然后用这个变量拼接上传文件保存的二级路径即可。 (3)最后一句就是连接到upfile.lua,进行后续处理。
3.创建一个upfile.lua,放到指定位置,例如/home/appadmin/nginx/conf/luascript/upfile.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.log(ngx.ERR, "failed to new upload: ",err)
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
form:set_timeout(1000)
string.split = function(s,p)
local rt = {}
string.gsub(s,'[^'..p..']+', function(w) table.insert(rt, w) end)
return rt
end
-- FILE LOCATION
local saveRootPath = "/home/appadmin/uploadFile/"
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
-- read fileName from 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
fileToSave = io.open(saveRootPath .. filename, "w+")
if not fileToSave then
ngx.say("failed to open file ", filename)
return
end
break
end
end
end
end
else if typ == "body" then
if fileToSave then
fileToSave:write(res)
end
else if 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("save file ok")
end
4.创建一个html文件测试,例如放到/home/appadmin/nginx/html/myupload.html ,内容如下:
<!DOCTYPE html>
<html>
<head>
<title>File Upload</title>
</head>
<body>
<form action="uploadFile" method="post" enctype="multipart/form-data">
<label for="testFileName">select file: </label>
<input type="file" name="testFileName" />
<input type="submit" name="upload" value="Upload" />
</form>
</body>
</html>
如果写在本地,action可以写成:
action="http://10.123.123.123/uploadFile"
直接访问nginx所在的那个路径。
5.如果测试成功,会有返回文件,内容为save file ok ,正是lua文件中配置的,然后在服务器对应路径就可以看到上传的文件了,到此结束;
如果报错,继续向下看。
6.如果发现upload.err.log文件中有上传文件后的报错信息(上方nginx配置的):
(1)如果报错找不到resty.upload,解决方法如下: 使用find命令,查找有没有upload.lua文件; 如果有,则把这个文件复制到报错信息中提示的路径下; (报错第一句会提示某个路径下没有找到upload.lua文件);
如果没有upload.lua文件,则需要安装,例如lua-resty-upload-0.10 ,安装方法参考下方或百度。
(2)如果报错找不到cjson/cjson.lua/cjson.so,解决方法如下: 可以安装lua-cjson-2.1.0.6 。
1.)先用find命令查看有没有cjson,因为如果安装的是resty版nginx的话,可能在[/home/appamin/nginx-1.13.6.2/build/bundle/lua-cjson-2.1.0.6]下已经有文件了,cd到这个路径即可。 1.5.)从网上下载这个tar.gz包,解压后cd到该路径下。 2.)vi Makefile,可以修改其中的安装路径;因为安装到默认路径可能会没有权限,所以修改:
#PREFIX = /usr/local
PREFIX = $(HOME)/lua
保存后退出vi。 3.)执行make命令(会读取Makefile文件并编译);如果报错找不到lua.h文件,则需要安装lua,例如LuaJIT-2.1-20180420 ,安装后用find找到该文件,复制到报错信息提示的路径下(如果安装时没有权限,同样修改安装路径即可);重新执行make命令。
4.)执行make install命令,安装成功后,就可以找到cjson.so文件了。
5.)把cjson.so复制到错误信息中提示找不到cjson.so的路径下即可。(不用管cjson/cjson.lua了,有cjson.so就可以了)
7.再次测试上传功能,应该可以成功了。
(如果还有哪些报错,可以留言,一起探讨解决)
三、总结
1.nginx应该选用openresty版本的。 2.修改nginx.conf,增加一个路径。 3.编写lua文件,用于实现文件上传。 4.编写前端html,用于自测。
5.文件删除功能也可以用nginx+lua实现,主要就是要写好lua,待后续研究。
|