nginx+lua实现文件上传总结(亲测可用)

  • Post author:
  • Post category:其他




一、需求说明

前端经常需要增加一些模板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

,文件内容如下:

-- 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

string.trim = function(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
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文件,用于实现文件上传。(例如上面编写的upfile.lua)

4.准备好cjson.so文件,放到lua同级目录。(例如放到upfile.lua同级目录下)

5.编写前端html,用于自测。

6.文件删除功能也可以用nginx+lua实现,主要就是要写好lua,待后续研究。



版权声明:本文为BHSZZY原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。