基于 lua-resty-upload 实现简单的文件上传服务
来源:互联网 发布:英敏特信息咨询 知乎 编辑:程序博客网 时间:2024/06/06 01:13
文章引用:
1 http://www.codexiu.cn/nginx/blog/11024/
前言:
参照 lua-resty-upload 模块结合Nginx实现对外提供一个url,利用post方式上传文件的lua脚本。测试方式可以利用postman直接调用对外url,以post方式上传文件。
在这里不对Nginx的配置做多余的说明,关于Nginx的配置上传模块可以参见百度。
lua-resty-upload 在 github 上的项目地址为:https://github.com/openresty/lua-resty-upload
一丶接收上传文件的lua脚本
--从环境变量LUA_PATH中搜索lua文件package.path = './lualib/resty/?.lua;' --从LUA_CPATH中搜索C文件package.cpath = './lualib/?.so;' --==========================================-- 获取上传文件名称--==========================================function get_filename(res) local filename = ngx.re.match(res,'(.+)filename="(.+)"(.*)') if filename then return filename[2] end end --==========================================-- 获取上传文件路径--==========================================function get_fileUploadPath() local obj = io.popen("cd") local path = obj:read("*all"):sub(1,-2) --记录当前lua脚本所在的绝对路径 --local cjson = require("cjson.safe") --local logs = {lua_script_absolutely_path = path} --local json = cjson.encode(logs) ngx.log(ngx.ERR, "lua_script_absolutely_path is: " .. path) path = path.sub(path, 1, string.len(path) - 16) .. "data/package_upload" --记录当前上传文件存储的绝对路径 --logs = {upload_file_absolutely_path = path} --json = cjson.encode(logs) ngx.log(ngx.ERR, "upload_file_absolutely_path is: " .. path) return pathend--==========================================-- 文件上传--==========================================function upload() local upload = require("upload") local chunk_size = 4096 local form, err = upload:new(nil,chunk_size,chunk_size) if not form then ngx.log(ngx.ERR, "failed to new upload: ", err) ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end local file local filelen=0 form:set_timeout(0) -- 1 sec local filename local osfilepath = get_fileUploadPath() local i=0 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 if res[1] ~= "Content-Type" then filename = get_filename(res[2]) if filename then i=i+1 filepath = osfilepath .. filename file = io.open(filepath,"w+") if not file then ngx.say("failed to open file ") return end else end end elseif typ == "body" then if file then filelen= filelen + tonumber(string.len(res)) file:write(res) else end elseif typ == "part_end" then if file then file:close() file = nil --调用agent的bat脚本,并用agent的返回值代替下面say的内容 local result = io.popen('test.bat') local returnValue = result:read("*all") ngx.say(returnValue) end elseif typ == "eof" then break else end end if i==0 then ngx.say("please upload at least one file!") return end end--开始调用上传文件脚本ngx.log(ngx.ERR, "\n")ngx.log(ngx.ERR, "------------------------------------------------------------------")ngx.log(ngx.ERR, "-------------start execute upload_package lua script--------------")ngx.log(ngx.ERR, "------------------------------------------------------------------")local request_method = ngx.var.request_methodif "POST" == request_method then get_fileUploadPath() upload()endngx.log(ngx.ERR, "------------------------------------------------------------------")ngx.log(ngx.ERR, "-------------end execute upload_package lua script--------------")ngx.log(ngx.ERR, "------------------------------------------------------------------")ngx.log(ngx.ERR, "\n")
二丶 lualib/resty/upload.lua 源码
通过阅读 lualib/resty/upload.lua 源码,该模块在解析文件上传请求的过程中,主要采用了简单的类似有限状态机的算法来实现的,在不同的状态由相应的 handler 进行处理,支持的状态包括如下状态:
1 STATE_BEGIN(1)
初始状态,是在 upload:new 实例化的时候初始化的,如下源码(只保留了主干):
function _M.new(self, chunk_size, max_line_size) local boundary = get_boundary() local sock, err = req_socket() local read2boundary, err = sock:receiveuntil("--" .. 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, state = STATE_BEGIN }, mt)end
2 STATE_READING_HEADER(2)
开始解析 HTTP 头部消息,一般在这个阶段主要用于解析出其中的文件名, boundary 等信息;相应的 handler 为 read_header;
3 STATE_READING_BODY(3)
开始解析 HTTP 包体,这个阶段就是读取文件内容;
4 STATE_EOF(4)
如果文件全部都解析和读取完后,则进入该状态,一般这个阶段表示文件都已经读取完;
这 4 个状态分别的 handler 为:
state_handlers = { read_preamble, read_header, read_body_part, eof}
这里要注意的是不同阶段/状态下 read 返回的结构不同,如在 STATE_READING_HEADER 下返回的结构是 “header”,{ key, value, line}
上传的文件会被保存在本地的路径 /home/steven/openresty/nginx/upload/ 下
三丶配置nginx.conf
添加 location /upfile 用于接收文件上传的 action,并通过 myupload.lua 来解析文件上传内容后保存至本地文件系统,如下:
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; } }}
- 基于 lua-resty-upload 实现简单的文件上传服务
- nginx基于lua-resty-upload实现文件上传
- 通过lua-resty-upload实现文件上传的例子
- Nginx+upload+lua 简单的文件上传
- commons-upload 实现文件的上传功能
- bootstrap upload 文件上传的实现过程
- lua-resty-kafka的使用
- upload文件的上传
- struts实现upload文件上传
- jquery file upload多文件上传的简单应用
- 简单的Struts upload上传
- 一个基于OpenResty的仿Yii的web框架 https://github.com/hylun/lua-resty-yii
- lua-resty-yii一个基于OpenResty的仿Yii的web框架
- OpenResty的lua-resty-template使用
- 使用common upload实现文件上传
- lua-resty-ssdb
- lua-resty-ssdb
- Python写的一个文件上传upload
- 一些常用的sql语句
- 执行kubectl exec -it报错分析
- maven的package与install命令区别
- py c 内嵌通信
- 回调函数模拟qsort
- 基于 lua-resty-upload 实现简单的文件上传服务
- table表格表头合并单元格问题
- undefined reference to `floor' 'fmod' 'pow' 'log10'
- 数组基础知识1
- 视觉学习二 ——在虚拟机中移植RMVision(一)
- 机器学习系列-AdaBoost
- 树形图界面的整合
- 流程与IT管理是未来IT行业发展的必经之路
- 发送邮件到qq邮箱、126邮箱后丢失样式