nginx+lua实现上传文件到OSS
目录
技术点
openResty
下载安装
示例
oss.lua 文件
测试代码 text.lua
nginx 配置
技术点
openResty
OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
openresty 官网
下载安装
请参考官网
示例
需要OpenResty 第三方模块,将第三方模块 拷贝到 lualib/resty 目录
- resty.http https://github.com.cnpmjs.org/ledgetech/lua-resty-http.git
- resty.oss https://github.com/362228416/lua-resty-oss.git
oss.lua 文件
--
-- Aliyun oss lua sdk
-- User: LinChao
-- Date: 2017/4/18
-- Time: 下午 5:24local http = require "resty.http"local _M = {__version = "0.01"
}local mt = {__index = _M}function new(oss_config)return setmetatable(oss_config, mt)
endfunction 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_namelocal url_s = "https://" .. headers['Host'] .. '/' .. object_nameif err then return nil, err endlocal res, err = self:_send_http_request(url, "PUT", headers, content)if not res thenerr = err or ''return errendreturn url_s, object_name, res.body
endfunction delete_object(self, object_name)local headers, err = self:_build_auth_headers('DELETE', nil, nil, object_name)local url = "http://" .. headers['Host'] .. '/' .. object_nameif err then return nil, err endlocal res, err = self:_send_http_request(url, "DELETE", headers)if 204 ~= res.status thenngx.log(ngx.ERR, res.body, err)return false, res.statusendreturn true
endfunction put_bucket(self, bucket)self.bucket = bucketlocal headers, err = self:_build_auth_headers('PUT')local url = "http://" .. headers['Host'] .. '/'if err then return nil, err endlocal res, err = self:_send_http_request(url, "PUT", headers)if not res thenreturn false, errendreturn true, nil, res.body
endfunction put_bucket_acl(self, bucket, acl)local current_bucket = self.bucketself.bucket = bucketlocal headers, err = self:_build_auth_headers('PUT', '', '', '', acl)self.bucket = current_bucketlocal url = "http://" .. headers['Host'] .. '/'if err then return nil, err endlocal res, err = self:_send_http_request(url, "PUT", headers)if not res thenreturn false, errendreturn true, nil, res.body
endfunction delete_bucket(self, bucket)local current_bucket = self.bucketself.bucket = bucketlocal headers, err = self:_build_auth_headers('DELETE')self.bucket = current_bucketlocal url = "http://" .. headers['Host'] .. '/'if err then return nil, err endlocal res, err = self:_send_http_request(url, "DELETE", headers)if not res thenreturn false, errendreturn true, nil, res.body
endfunction _sign(self, str)local key = ngx.encode_base64(ngx.hmac_sha1(self.secretKey, str))return 'OSS '.. self.accessKey .. ':' .. key
endfunction _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
endfunction _build_auth_headers(self, verb, content, content_type, object_name, acl)local bucket = self.bucketlocal endpoint = self.endpointlocal bucket_host = bucket .. "." .. endpointlocal 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 .. ":" ..acllocal resource = '/' .. bucket .. '/' .. (object_name or '')local CL = string.char(10)local check_param = verb .. CL .. MD5 .. CL .. _content_type .. CL .. Date .. amz .. CL .. resourcelocal headers = {['Date'] = Date,['Content-MD5'] = MD5,['Content-Type'] = _content_type,['Authorization'] = self:_sign(check_param),['Connection'] = 'keep-alive',['Host'] = bucket_host}headers[aclName] = aclreturn 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 = _signreturn _M
测试代码 text.lua
local upload = require "resty.upload"
local oss = require "resty.oss"
local http = require "resty.http"-- 获取上传的文件
function readFile()local chunk_size = 4096local form, err = upload:new(chunk_size)-- form:set_timeout(20000)local file = {}if not err thenwhile true dolocal typ, res, err2 = form:read()if not typ thenerr = err2print("failed to read: ", err2)breakendif typ == 'header' and res[1] == 'Content-Disposition' thenlocal filename = string.match(res[2], 'filename="(.*)"')file.name = filenameendif typ == 'header' and res[1] == 'Content-Type' thenfile['type'] = res[2]endif typ == 'body' and file thenfile[typ] = (file[typ] or '') .. resendif typ == "eof" thenbreakendendendreturn file, err
end-- 根据文件类型判断 上传到那个bucket
function ulpoadBucket(file_type)local type=''if string.find(file_type,'video',1) thentype ='campusvideo'elseif string.find(file_type,'audio',1) thentype='campusrecord'elseif string.find(file_type,'image',1) thentype='campusfile'elsetype='campus002'endreturn 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 dotable.insert(tb,seed[math.random(1,16)])endlocal 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))
endlocal file, err = readFile()
if err thenngx.say('{"status":-1,"msg":"上传失败"}')
elselocal oss_config ={accessKey='xxxxx',secretKey='xxxx',bucket='xxx',endpoint='oss-cn-beijing.aliyuncs.com'}local type = ulpoadBucket(file.type)oss_config['bucket']=typelocal client = oss.new(oss_config)local stuff = file.name:match(".+%.(%w+)$")local file_name = guid() .. '.' .. stufflocal 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;}} }
相关文章:

使用CEfSharp之旅(7)CEFSharp 拦截 http 请求 websocket 内容
使用CEfSharp之旅(7)CEFSharp 拦截 http 请求 websocket 内容 原文:使用CEfSharp之旅(7)CEFSharp 拦截 http 请求 websocket 内容版权声明:本文为博主原创文章,未经博主允许不得转载。可点击关注博主 &…

sqlserver查询一个表的字段信息
select count(*) from syscolumns where idobject_id(表名) 转载于:https://www.cnblogs.com/dongpo888/archive/2011/05/11/2043370.html

ASP.NET无刷新客户端回调
首先说一下:Page.ClientScript 用于管理脚本、注册脚本和向页添加脚本。 返回结果:一个 System.Web.UI.ClientScriptManager 对象。 ClientScriptManager对象 是一些 在 Web 应用程序中定义用于管理客户端脚本的方法,其中有一个方法重载:stri…

common lisp里的几个操作符
setf 赋值操作符,定义一个全局变量。返回值是最后一个赋值的结果。 let 局部变量操作符。let表达式有两部分组成。第一部分是任意多的变量赋值,他们被包裹在一个()中,第二部分是任意数量的表示式作为 let 的函数体。let 表达式的返回值为 最…

敏捷宣言遵循的十二条原则
敏捷宣言遵循的十二条原则Twelve Principles behind the Agile Manifesto 我们遵循以下原则: We follow these principles: 我们最重要的目标,是通过持续不断地及早交付有价值的软件使客户满意。Our highest priority is to satisfy the customer throug…

微信公众号开发的一些配置
1、开发者ID(AppID) 开发者ID是公众号开发识别码,配合开发者密码可调用公众号的接口能力。 2、开发者密码(AppSecret) 开发者密码是校验公众号开发者身份的密码,具有极高的安全性。切记勿把密码直接交给第三…

javascript-对混合字母/数字数组进行排序
[A1, A10, A11, A12, A2, A3, A4, B10, B2, F1, F12, F3]将其排序为: [A1, A2, A3, A4, A10, A11, A12, B2, B10, F1, F3, F12] var reA /[^a-zA-Z]/g; var reN /[^0-9]/g;function sortAlphaNum(a, b) {var aA a.replace(reA, "");var bA b.replace…

国王验毒酒问题
国王召开宴会,一共有1000桶葡萄酒。邪恶的刺客在其中一桶酒里下了致命的毒。人们只知道有且仅有一桶酒被下毒,却不知道是哪一桶。现在你可以拿小白鼠做实验,小白鼠可以同时喝下多个桶的取样结果,且无视稀释效果喝到就死࿰…

Nodejs核心模块之net和http的使用详解
前言 net和http模块都是node核心模块之一,他们都可以搭建自己的服务端和客户端,以响应请求和发送请求。 net模块服务端/客户端 这里写的net模块是基于tcp协议的服务端和客户端,用到net.createServer和net.connect实现的一个简单请求与响应的d…

NODEJS 使用 XLSX模块导出excel文件
参考:https://www.itranslater.com/qa/details/2582439815438402560 生成excel /*** 用于排序* param a* param b* returns {number}*/ function sortAlphaNum(a, b) {let reA /[^a-zA-Z]/g;let reN /[^0-9]/g;let aA a.replace(reA, "");let bA b.re…

poj 3352
题意:一个连通的无向图,求至少需要添加几条边,救能保证删除任意一条边,图仍然是连通的。 思路:边的双连通图。其实就是要求至少添加几条边,可以使整个图成为一个边双连通图。用tarjan算法(求割点割边)求出l…

oracle删除大表的数据的方法
今天在公司中碰到访问表数据(test 表)速度非常慢,简单的一个select 语句花了10多分钟, 后来查询一下表的数据量,一共有278万多条数据,而且这个数据表的数据大都过期了,对于现在的业务没什么用。可悲的是这个表竟然也没…

ClickHouse 学习
DDL 添加数据库字段 alter table user_tags add column last_subject String; alter table user_tags add column class_trust_valids Int8; 删除列 ALTER TABLE [db].name [ON CLUSTER cluster] DROP COLUMN ... 日期函数 当toDate 遇到空的串报异常时 select toDate();…
zTree实现节点修改的实时刷新
一、应用场景 在实际应用中会遇到动态操作树各节点的需求,在增加树节点后如何实时动态刷新树就十分有必要了。二、项目实践 比如要在test1234节点下新建子节点,首先要选中test1234节点,添加成功后,根据test1234结点的TID去后台请求…

magento常用软件
常见问题: 1. 装完插件导致后台配置出现 Access denied 信息,需要重置账号权限,方可恢复正常。 2. 大多数无法安装插件时,请删除 /downloader/pearlib/pear.ini 文件,最后到 Connect Manager 里保存下设置&#…

连接惠普打印机(通过WIFI)
第一步 找到打印机型号 第二步 到惠普官方网站下载对应驱动 第三步 安装驱动 第四步 安装驱动后选择WIFI连接(IP在打印机显示屏幕上显示,如果输入打印机屏幕IP连接失败;需要获取打印机真正的IP地址,在HP设备工具箱中获取ÿ…
ADO.NET的连接模式
1、连接模式:客户机一直保持和数据库服务器的链接,适合数据传输量少,系统规模不大、客户机和服务器在同一网络内的环境。 使用连接模式下数据访问的步骤如下: a、使用connection对象连接数据库 b、使用command(命令&am…

App调用safar
/调用safar打开网页 [[UIApplication sharedApplication] openURL:[NSURL URLWithString:"http://www.cnblogs.com/foxmin"]]; 调用app store (省略号后面加的是产品的id等一些参数) // [[UIApplication sharedApplication] openURL:[NSURL URLWithString:"i…

Spring Boot 整合Redis 实现缓存
本文提纲一、缓存的应用场景二、更新缓存的策略三、运行 springboot-mybatis-redis 工程案例四、springboot-mybatis-redis 工程代码配置详解运行环境:Mac OS 10.12.xJDK 8 Redis 3.2.8Spring Boot 1.5.1.RELEASE一、缓存的应用场景 什么是缓存?在互联网…

Sqlite3支持的数据类型 日期函数 Sqlite3 函数
Sqlite3支持的数据类型 NULL INTEGER REAL TEXT BLOB 但实际上,sqlite3也接受如下的数据类型: smallint 16 位元的整数。 interger 32 位元的整数。 decimal(p,s) p 精确值和 s 大小的十进位整数,精确值p是指全部有几个数(digits)大小值&…

Element el-switch 组件样式修改 将文字显示到组件内
Element el-switch 现在的样式无法将文字显示到组件内 ,需要自己修改样式。具体如下 <el-switch:disabled"sitem.select.length-1"class"switch"v-model"sitem.or"active-color"#13ce66"inactive-color"#409EFF&qu…

jquery中输入验证中一个不错的效果
在表单的输入验证中,经常要当用户没能正确输入后,要提示“XXXX输入错误”这一类的信息,如何能搞到动态一点呢,今天发现jquery中的一个不错的效果,笔记之。 1 包含jquery <script src"images/jquery-1.2.6.min…

【2018.2.25】c++预习练习
学了一学期c语言之后预习c,一些最基础的东西做起来还是得心应手的,先练练手感?C primer plus 和教材同步学习,大概会比上学期抓瞎学习要好得多吧。 1 #include<iostream>2 int main()3 {4 using namespace std;5 cout <<…

在做项目中遇到的JS问题
name和value: 例如: <input type"text" name"txt"/> name用于定义这个input收到的值的变量名,在上面的input输入“hello",那么就有txt"hello";用于dom操作取值 在用js改变某个div属性进行传值操作时࿰…

用Duplex实现消息广播
http://blog.csdn.net/fangxinggood/archive/2011/01/15/6142861.aspx WCF中定义3种消息交换模式: 1. Request/Reply; 2. One-Way; 3. Duplex。 Request/Reply 是缺省模式,即同步调用。在调用服务方法后需要等待服务的消息返回,即便该方法返…

mongoose手动生成ObjectId
如果需要手动生成使用mongoose.Types.ObjectId()方法。 var mongoose require(mongoose); var id mongoose.Types.ObjectId();

Coolpad F61刷机解锁成功
这几天是高校开学的日子,各大运营商纷纷进驻校园,打出种种优惠,抢新鲜用户。 我一直觉得我现在的移动号码收费太贵,每个月不知不觉就是100多块,对我这个以公司为家(公司电话就是我的电话)的宅人而言,是有点夸张了。特别是和国外的运营商相比,如果你有朋友在国外&…

Django 数据库
一、操作数据库 Django配置连接数据库: 在操作数据库之前,首先先要连接数据库。这里我们以配置MySQL为例来讲解。Django连接数据库,不需要单独的创建一个连接对象。只需要在settings.py文件中做好数据库相关的配置就可以了。示例代码如下&…

MapReduce 中 UDF、UDAF、UDTF
UDF UDF只能实现一进一出的操作,如果需要实现多进一出,则需要实现UDAFUDF函数可以直接应用于select语句,对查询结构做格式化处理后,再输出内容 UDAF UDFA是用户自定义的聚类函数,是基于表的所有记录进行的计算操作 …

计算机网络面试知识总结1
1.TCP报头格式 TCP协议头至少20个字节 (1)源端口 16位,主要用于标志报文的返回地址,其中包含初始化通信的端口 (2)目的端口 16位,指明了要把数据传送到哪 (3)序列号 32位…