美文网首页零星知识点
使用OpenResty搭建简单的文件服务器

使用OpenResty搭建简单的文件服务器

作者: Martain | 来源:发表于2020-05-21 14:45 被阅读0次

    前言

    前几天使用nginx+nginx_upload_module+python(回调处理程序)搭建了一个简单的文件服务器,网上很多人都建议使用Lua去扩展nginx的功能,所以琢磨了下如何使用Lua语言去对nginx去做功能扩展,网上查阅了许多资料,发现环境搭建还是比较麻烦的,需要安装LuaJITnginx的还需要一起编译ngx_devel_kitlua-nginx-module模块,然后发现了openresty

    之前在了解kong网关的时候知道过openresty,但是没有去了解研究过,这次的机会恰好让我了解学习了一下。

    关于openresty

    官网官方博客官方论坛

    OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

    OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。

    OpenResty® 的目标是让你的Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。

    ​ -- 摘自官网

    开始搭建

    安装OpenResty

    关于OpenResty的安装方法官方文档有非常详细的说明,而且非常全面,可能和章亦春的性格有关吧,非常简单,快速。

    • 直接使用安装工具安装(推荐)

      # add the yum repo:
      wget https://openresty.org/package/centos/openresty.repo
      sudo mv openresty.repo /etc/yum.repos.d/ 
      # update the yum index:
      sudo yum check-update
      sudo yum install -y openresty
      
    • 其他参考这里

    我是使用yum安装的,默认的安装位置在/usr/local/openresty

    [root@cloudfile openresty]# pwd
    /usr/local/openresty
    [root@cloudfile openresty]# ls
    bin  conf  COPYRIGHT  luajit  lualib  nginx  openssl  pcre  site  zlib
    

    编写文件处理的Lua脚本

    • 文件位置:/usr/local/openresty/nginx/conf/lua/update.lua
    -- upload.lua
    --==========================================
    -- 文件上传
    --==========================================
    -- 导入模块
    local upload = require "resty.upload"
    local cjson = require "cjson"
    -- 定义回复的结构
    -- 基本结构
    local function response(status,msg,data)
        local res = {}
        res["status"] = status
        res["msg"] = msg
        res["data"] = data
        local jsonData = cjson.encode(res)
        return jsonData
    end
    -- 默认成功的response
    local function success()
        return response(0,"success",nil)
    end
    -- 默认带数据的response
    local function successWithData(data)
        return response(0,"success",data)
    end
    -- 失败的response
    local function failed( msg )
        return response(-1,msg,nil)
    end
    -- end
    local chunk_size = 4096
    -- 获取请求的form
    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) 
        ngx.say(failed("没有获取到文件"))
    end
    form:set_timeout(1000)
    -- 定义 字符串 split 分割 属性
    string.split = function(s, p)
        local rt= {}
        string.gsub(s, '[^'..p..']+', function(w) table.insert(rt, w) end )
        return rt
    end
    -- 定义 支持字符串前后 trim 属性
    string.trim = function(s)
        return (s:gsub("^%s*(.-)%s*$", "%1"))
    end
    -- 文件保存的根路径
    local saveRootPath = ngx.var.store_dir
    -- 保存的文件对象
    local fileToSave
    -- 标识文件是否成功保存
    local ret_save = false
    -- 实际收到的文件名
    local rawFileName
    -- 实际保存的文件名
    local filename
    -- 开始处理数据
    while true do
        -- 读取数据
        local typ, res, err = form:read()
        if not typ then
            ngx.say(failed(err))
            return
        end
        -- 开始读取 http header
        if typ == "header" then
            -- 解析出本次上传的文件名
            local key = res[1]
            local value = res[2]
            if key == "Content-Disposition" then
                -- 解析出本次上传的文件名
                -- form-data; name="keyName"; filename="xxx.xx"
                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, "=")
                        -- 实际的文件名
                        rawFileName = string.sub(kvfile[2], 2, -2)
                        -- 重命文件名
                        filename = os.time().."-"..rawFileName
                        if filename then
                            -- 打开(创建)文件
                            fileToSave = io.open(saveRootPath .."/" .. filename, "w+")
                            if not fileToSave then
                                -- ngx.say("failed to open file ", filename)
                                ngx.say(failed("打开文件失败"))
                                return
                            end
                            break
                        end
                    end
                end
            end
        elseif typ == "body" then
            -- 开始读取 http body
            if fileToSave then
                -- 写入文件内容
                fileToSave:write(res)
            end
        elseif 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
        local uploadData = {}
        uploadData["file"] = rawFileName
        uploadData["url"] = "http://xxx.com/download/"..filename
        ngx.say(successWithData(uploadData))
    else
        ngx.say(failed("系统异常"))
    end
    
    

    编写nginx配置文件

    • 文件位置:/usr/local/openresty/nginx/conf/nginx.conf
    user root;
    worker_processes  20;
    error_log  logs/error.log notice;
    events {
        worker_connections  1024;
    }
    http {
        include       mime.types;
        default_type  application/octet-stream;
        server {
            listen       80;
            server_name  localhost;
            # 最大允许上传的文件大小
            client_max_body_size 300m; 
            set $store_dir "/var/www/download"; # 文件存储路径
            # 文件上传接口:http://xxx.com/uploadfile
            location /uploadfile {
                # 实现文件上传的逻辑
              content_by_lua_file conf/lua/upload.lua; 
            }
            # 文件下载入口: http://xxx.com/download
            location /download {
                alias /var/www/download;
                autoindex on;
                autoindex_localtime on; 
            }
            # redirect server error pages to the static page /50x.html
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
        }
    }
    

    启动测试

    这里启动nginx的方式和普通的nginx是一样的:

    • 启动:/usr/local/openresty/nginx/sbin/nginx
    • 关闭:/usr/local/openresty/nginx/sbin/nginx -s stop
    • 重新加载配置:/usr/local/openresty/nginx/sbin/nginx -s reload

    上传文件

    POST /uploadfile

    上传文件

    下载文件

    访问GET /download即可

    相关文章

      网友评论

        本文标题:使用OpenResty搭建简单的文件服务器

        本文链接:https://www.haomeiwen.com/subject/vvwzohtx.html