Today I learned about the Lua-resty-upload module, and based on the Lua-resty-upload module simple implementation of a basic form file upload service.
Lua-resty-upload's project address on GitHub is: https://github.com/openresty/lua-resty-upload
From the implementation can be seen, in fact, the implementation of upload service is relatively simple, a source file Lualib/resty/upload.lua, the total number of lines of code is only 300 lines.
Below I have organized the process of building a file upload service:
1, the front page is very simple, is to use the form of input file to trigger the file upload, the code is as follows:
<!--myupload.html--><! DOCTYPE html>
The corresponding myupload.html file is deployed under openresty/nginx/html/.
2, implement the LUA code to receive the file Upload form information and save to the local path, the code is as follows:
-- myupload.lua--==========================================-- File Upload--================================ ==========local upload = require "Resty.upload" local cjson = require " Cjson "Local chunk_size = 4096local 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) Endform:set_timeout (-- ) string split split string.split = function (s, p) local rt= {} string.gsub (s, ' [^ ' ... P.. ') + ', function (w) table.insert (rt, w) end ) return rtend-- supports strings before and after trimstring.trim = function (s) return (S:gsub ("^%s* (.- %s*$ ", "%1 ")) end-- file saved root path Local saverootpath = "/home/steven/openresty/nginx/upload/"-- saved file object local filetosave--file is saved successfully local Ret_save = falsewhile true do local typ, res, err = form:read () if not typ then ngx.say ("failed to read: ", err) return end if typ == "Header" then -- start reading http header -- parse out the file name of this upload local key = res[1] local value = res[2] if key == "Content-disposition" then -- parse out the file name of this upload -- 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, "=") &nbSp; 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 elseif typ == "Body" then -- start reading http body if fileToSave then filetosave:wRite (RES) end elseif typ == "Part_end" then -- file write end, close file if fileToSave then filetosave:close () fileToSave = nil end ret_save = true elseif typ == "EOF" then -- End of File read break else ngx.log (ngx.info, "do other things") endendif ret_save theN ngx.say ("Save file ok") end
By reading the Lualib/resty/upload.lua source code, the module in the process of parsing the file upload request, the main use of a simple similar finite state machine algorithm to achieve, in different states by the corresponding handler processing, supported by the status of the following States include:
state_begin (1), the initial state, is initialized at the time of Upload:new instantiation, the following source code (only retained the backbone):
Function _m.new (self, chunk_size, max_line_size) local boundary = get_boundary () local sock, err = req_socket () local read2boundary, err = sock:receiveuntil ("--" &NBSP; boundary) local read_line, err = sock:receiveuntil ("\ r \ n") return setmetatable ({ sock = sock, size = chunk_size or chunk_size , line_size = max_line_size or max_line_ size, read2boundary = read2boundary, read_line = read_line, boundary = boundary, &nBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;STATE&NBSP;=&NBSP;STATE_BEGIN&NBSP;&NBSP;&NBSP;&NBSP;},&NBSP;MT) End
State_reading_header (2), start parsing HTTP header message, generally at this stage is mainly used to parse out the file name, boundary and other information; the corresponding handler is Read_header ;
state_eof (4), if all the files are parsed and read, then enter the state, generally this stage indicates that the file has been read;
The handler of these 4 states are:
State_handlers = {read_preamble, Read_header, Read_body_part, EOF}
-It is important to note that the structure of the read return in different stages/states is different, as the structure returned under state_reading_header is "HEADER", {key, value, line}
-The uploaded file will be saved in the local path /home/steven/openresty/nginx/upload/
3, configure nginx.conf, add location/upfile to receive File upload action, and through Myupload.lua to parse the file upload content after saving to the local file system, as follows:
http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 19080; server_name localhost; location / { root html; index index.html index.htm; } Location /upfile { content_by_lua_file lua/myupload.lua; } # redirect server error pages to the static page /50x.html error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }}
This article is from the "Quiet lunatic" blog, please make sure to keep this source http://quietmadman.blog.51cto.com/3269500/1766034
Simple file uploading service based on Lua-resty-upload