nginx+lua实现上传文件到OSS

目录

技术点

openResty

下载安装

示例

oss.lua 文件

测试代码 text.lua

nginx 配置


技术点

openResty

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

openresty 官网

下载安装

请参考官网

示例

需要OpenResty 第三方模块,将第三方模块 拷贝到 lualib/resty 目录

 

oss.lua 文件

--
-- Aliyun oss lua sdk
-- User: LinChao
-- Date: 2017/4/18
-- Time: 下午 5:24

local http = require "resty.http"

local _M = {
    __version = "0.01"
}

local mt = {__index = _M}

function new(oss_config)
    return setmetatable(oss_config, mt)
end

function put_object(self, content, content_type, object_name)
    local headers, err  = self:_build_auth_headers('PUT', content, content_type, object_name)
    local url     = "http://" .. headers['Host'] .. '/' .. object_name
    local url_s = "https://" .. headers['Host'] .. '/' .. object_name
    if err then return nil, err end
    local res, err = self:_send_http_request(url, "PUT", headers, content)
    if not res then
        err	= err or ''
        return err
    end
    return 	url_s, object_name, res.body
end

function delete_object(self, object_name)
    local headers, err = self:_build_auth_headers('DELETE', nil, nil, object_name)
    local url = "http://" .. headers['Host'] .. '/' .. object_name
    if err then return nil, err end
    local res, err = self:_send_http_request(url, "DELETE", headers)
    if 204 ~= res.status then
        ngx.log(ngx.ERR, res.body, err)
        return false, res.status
    end
    return true
end

function put_bucket(self, bucket)
    self.bucket = bucket
    local headers, err  = self:_build_auth_headers('PUT')
    local url     = "http://" .. headers['Host'] .. '/'
    if err then return nil, err end
    local res, err = self:_send_http_request(url, "PUT", headers)
    if not res then
        return false, err
    end
    return 	true, nil, res.body
end

function put_bucket_acl(self, bucket, acl)
    local current_bucket = self.bucket
    self.bucket = bucket
    local headers, err  = self:_build_auth_headers('PUT', '', '', '', acl)
    self.bucket = current_bucket
    local url     = "http://" .. headers['Host'] .. '/'
    if err then return nil, err end
    local res, err = self:_send_http_request(url, "PUT", headers)
    if not res then
        return false, err
    end
    return 	true, nil, res.body
end

function delete_bucket(self, bucket)
    local current_bucket = self.bucket
    self.bucket = bucket
    local headers, err  = self:_build_auth_headers('DELETE')
    self.bucket = current_bucket
    local url     = "http://" .. headers['Host'] .. '/'
    if err then return nil, err end
    local res, err = self:_send_http_request(url, "DELETE", headers)
    if not res then
        return false, err
    end
    return 	true, nil, res.body
end

function _sign(self, str)
    local key = ngx.encode_base64(ngx.hmac_sha1(self.secretKey, str))
    return 'OSS '.. self.accessKey .. ':' .. key
end

function _send_http_request(self, url, method, headers, body)
    local httpc = http.new()
    httpc:set_timeout(30000)
    local res, err = httpc:request_uri(url, {
        method = method,
        headers = headers,
        body = body
    })
    httpc:set_keepalive(30000, 10)
    return res, err
end

function _build_auth_headers(self, verb, content, content_type, object_name, acl)
    local bucket            =   self.bucket
    local endpoint          =   self.endpoint
    local bucket_host       =   bucket .. "." .. endpoint
    local Date              =   ngx.http_time(ngx.time())
    local acl               =   acl or 'public-read'
    local aclName           =   "x-oss-acl"
    local MD5               =   ngx.encode_base64(ngx.md5_bin(content))
    local _content_type     =   content_type or  "application/octet-stream"
    local amz               =   "\n" .. aclName .. ":" ..acl
    local resource          =   '/' .. bucket .. '/' .. (object_name or '')
    local CL                =   string.char(10)
    local check_param       =   verb .. CL .. MD5 .. CL .. _content_type .. CL .. Date .. amz .. CL .. resource
    local headers  =	{
        ['Date']            =	Date,
        ['Content-MD5']		=	MD5,
        ['Content-Type']	=	_content_type,
        ['Authorization']	=	self:_sign(check_param),
        ['Connection']		=	'keep-alive',
        ['Host']            =   bucket_host
    }
    headers[aclName]		=	acl
    return headers
end

-- public
_M.new = new
_M.put_object = put_object
_M.delete_object = delete_object
_M.put_bucket = put_bucket
_M.put_bucket_acl = put_bucket_acl
_M.delete_bucket = delete_bucket

-- private
_M._build_auth_headers = _build_auth_headers
_M._send_http_request = _send_http_request
_M._sign = _sign

return _M

测试代码 text.lua

local upload = require "resty.upload"
local oss = require "resty.oss"
local http = require "resty.http"

-- 获取上传的文件
function readFile()
    local chunk_size = 4096
    local form, err = upload:new(chunk_size)
    -- form:set_timeout(20000)
    local file = {}
    if not err then
        while true do
            local typ, res, err2 = form:read()
            if not typ then
                err = err2
                print("failed to read: ", err2)
                break
            end
            if typ == 'header' and res[1] == 'Content-Disposition' then
                local filename = string.match(res[2], 'filename="(.*)"')
                file.name = filename
            end
            if typ == 'header' and res[1] == 'Content-Type' then
                file['type'] = res[2]
            end
            if typ == 'body' and file then
                file[typ] = (file[typ] or '') .. res
            end
            if typ == "eof" then
                break
            end
        end
    end
    return file, err
end

-- 根据文件类型判断 上传到那个bucket
function ulpoadBucket(file_type)
    local type=''
    if string.find(file_type,'video',1) then
        type ='campusvideo'
    elseif string.find(file_type,'audio',1) then
        type='campusrecord'
    elseif  string.find(file_type,'image',1) then
        type='campusfile'
    else
        type='campus002'
    end
    return type 
end

--生成UUId
function guid()
    local seed={'e','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}
    local tb={}
    for i=1,32 do
        table.insert(tb,seed[math.random(1,16)])
    end
    local sid=table.concat(tb)
    return string.format('%s-%s-%s-%s-%s',
        string.sub(sid,1,8),
        string.sub(sid,9,12),
        string.sub(sid,13,16),
        string.sub(sid,17,20),
        string.sub(sid,21,32)
    )
end

local file, err = readFile()
if err then
    ngx.say('{"status":-1,"msg":"上传失败"}')
else
    local oss_config ={
        accessKey='xxxxx',
        secretKey='xxxx',
        bucket='xxx',
        endpoint='oss-cn-beijing.aliyuncs.com'
    }
    local type = ulpoadBucket(file.type)
    oss_config['bucket']=type
    local client = oss.new(oss_config)
    local stuff = file.name:match(".+%.(%w+)$")
    local file_name = guid() .. '.' .. stuff
    local url = client:put_object(file.body,file.type,file_name)
    ngx.say('{"status":0,"msg":"'..url..'"}')
end    


nginx 配置


#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        server_name  localhost;
        resolver 8.8.8.8;
        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

        location /hello {
            client_body_buffer_size 20M;
            client_max_body_size  50M;
            default_type application/json;
            content_by_lua_file lua/test.lua;
        }

        
    } 

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

古月_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值