把之前的报错图片上报挪到腾讯云的CloudBase
先来个效果 看右半边
说下结论,其实是一些最基本的认知
先给腾讯云的CloudBase(TCB)点个赞
先说云函数:
就目前的使用体验来说,云函数中的nodejs跑起来和在自己本机跑nodejs是没什么区别的,也就是说,本地的nodejs可以安装依赖,可以进行网络请求,可以读写硬盘,云开发中的nodejs也一样可以。
再说云数据库和云存储
自己电脑上跑的nodejs,和云函数的nodejs一样,都能访问云数据库和云存储。
换句话说就是,云存储或者云数据库是能通过网络来访问的,它和云函数是分开的两个世界的东西(通过网络建立连接),就像自己可以在自己的电脑上通过网络访问云存储或者云数据库一样。
而云函数,其实就是一个nodejs的容器(可以说是有全部功能和权限的nodejs),只不过他限定的请求的入口函数。
开发记录
第一步是在本地弄一个nodejs的项目,大致的结构如下图所示:
当然,官方一点的做法是通过命令行tcb init
来初始化一个项目
D:\>cd tcb_test
D:\tcb_test>tcb init
√ 选择关联环境 · dbliu - [dbliu-186f3d:空]
√ 请输入项目名称 · cloudbase-test
√ 选择开发语言 · Node
√ 选择云开发模板 · Hello World
√ 创建项目 cloudbase-test 成功!
i 👉 执行命令 cd cloudbase-test 进入项目文件夹!
i 👉 执行命令 cloudbase functions:deploy app 部署云函数
i 🎉 欢迎贡献你的模板 👉
i https://github.com/TencentCloudBase/cloudbase-templates
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
https://github.com/TencentCloudBase/cloudbase-templates
里有很多的模板,其中我感兴趣的有:
- node-trigger:Node 触发器示例(https://github.com/TencentCloudBase/cloudbase-templates/tree/master/nest-starter)
- nest-starter: nestjs 示例(刚好最近有研究nestjs)(https://github.com/TencentCloudBase/cloudbase-templates/tree/master/nest-starter)
有了项目后,需要安装需要的依赖
安装依赖
需要安装的依赖有
"dependencies": {
"tcb-admin-node": "latest",
"qiniu": "^7.3.1",
}
2
3
4
tcb-admin-node
:腾讯云开发提供的nodejs sdk
,让您在自己的服务端(或者腾讯云云函数或者CVM等)使用 Node.js 访问 TCB 的服务,如云函数调用,文件上传下载,数据库集合文档操作等。qiniu
:七牛云提供的nodejs sdk
,用于管理七牛云的cdn。之前用的cdn是qiniu的,现在也懒得改(主要是想看看在tcb中,能否通过http请求获取外网的数据,然后看看如何添加依赖)
本地编写代码并调试
接口1:
接口功能:
- 获取七牛云用于上传图片的token
- 在数据库中记录图片的文件名和日期
async function upload_info_and_get_upload_token_and_key(ext_info) {
//简单上传凭证
const options = {
scope: bucket,
};
const putPolicy = new qiniu.rs.PutPolicy(options);
let token = putPolicy.uploadToken(mac);
const db = tcb.database();
const _ = db.command;
const collection = db.collection(dbColName);
let res = await collection.add({
unix: new db.serverDate(),//服务端当前时间
ext_info: ext_info
});
return {
token: token,
id: res.id
};
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
客户端通过该接口获取到上传图片所需的token和文件名后,会把客户端崩溃时的截图上传到七牛云cdn。
接口2
获取列表(报错图片的名称和日期)
//page 第几页,每一页返回10条数据
async function get_upload_img_list(page) {
page = parseInt(page) || 1;
const db = tcb.database();
const _ = db.command;
const collection = db.collection(dbColName);
let list_info = [];
let response = {
page: page,//当前是第几页,用于分页显示
list: list_info
};
let res = await collection.skip((page - 1) * 10).limit((page - 1) * 10 + 9).orderBy("unix","desc").get();
for (let id of res.data) {
let info = {};
info.id = id._id;
info.unix = id.unix.getTime();
info.ext_info = id.ext_info;
list_info.push(info);
}
res = await collection.count()
response.total = res.total;//总共有多少条数据,用于分页显示
return response
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
数据库相关的操作
tcb云数据库的操作主要看文档:
表table
/集合collection
)的创建
(可以通过代码创表table
/集合collection
,也可以手动在后台创建
创建集合的代码示例:https://cloud.tencent.com/document/product/876/18441#createcollection
建立字段的索引
获取列表的接口中,用到的分页,也用到了排序orderBy("unix","desc")
,所以最好建立一个索引,比如,下图为unix字段建立了索引
提交部署
在本地测试功能可以正常跑了以后,就可以将代码提交到云函数和云静态网站托管上去了。
让云函数能够处理HTTP请求
具体参看文档:文档中心 > 云开发 CloudBase > 开发指南 > 云函数管理 > HTTP 触发
开通http触发后,通过浏览器发送过来的请求,会变成下面的样子传入云函数的入口函数中。
以 https://域名/触发路径?action=get_upload_img_list 请求为例,收到的数据如下:
{
"body": "",
"headers": {
"accept": "*/*",
"accept-encoding": "gzip, deflate, br",
"cache-control": "no-cache",
"connection": "keepalive",
"content-length": "89",
"content-type": "application/x-www-form-urlencoded",
--略-----------------
},
"httpMethod": "GET",
"isBase64Encoded": false,
"path": "/",
"queryStringParameters": {
"action": "get_upload_img_list"
},
"requestContext": {
--略-----------------
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
在云函数中,处理请求的入口需要修改一下:
// 返回输入参数
exports.main = async (event, context, callback) => {
//console.log(event);
if(event.httpMethod==="GET" || event.httpMethod==="POST"){
//是http的请求
if(event.queryStringParameters.action && event.queryStringParameters.action === 'upload_info_and_get_upload_token_and_key'){
let res = await upload_info_and_get_upload_token_and_key();
// callback(null, res);
return res
}
if(event.queryStringParameters.action && event.queryStringParameters.action === 'get_upload_img_list'){
let res = await get_upload_img_list(event.queryStringParameters.page);
// callback(null, res);
return res
}
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
云函数:开启定时任务,删除30天前的图片(七牛云中的)和数据库中的信息(tcb云数据库中的)
文档中心 > 云开发 CloudBase > 开发指南 > 云函数管理 > 定时触发器
也可以参照Demo : https://github.com/TencentCloudBase/cloudbase-templates/blob/master/node-trigger
设置好触发器后,假设设置的触发器为(每5分钟触发一次):
"triggers": [
{ "name": "trigger", "type": "timer", "config": "* */5 * * * * *" }
],
2
3
则触发后,云函数的event会收到如下数据:
{
"Message": "",
"Time": "2020-06-05T13:07:33Z",
"TriggerName": "trigger",
"Type": "Timer"
}
2
3
4
5
6
本地编写代码加模拟请求测试
直接在本地用假数据模拟一次请求,测试通过后,再同步到云函数中去。
// 返回输入参数
exports.main = async (event, context, callback) => {
//---------------省略其他代码---------------
if (event.TriggerName==="trigger" && event.Type==="Timer"){
return await delete_err_image_30();
}
};
2
3
4
5
6
7
8
9
10
//删除超过指定天数的图片
async function delete_err_image_30() {
const db = tcb.database();
const _ = db.command;
const collection = db.collection(dbColName);
//30天前的时间点
let delete_day = new db.serverDate({
offset: -(30 * 24 * 60 * 60* 1000)
});
//由于七牛云的批量删除不能超过1000个文件,所有这里最多取1000条数据
let res = await collection.limit(1000).orderBy("unix","asc").where({
unix : _.lt(delete_day)
}).get();
if (res.data.length && res.data.length>0){
//删除腾讯云数据库里的数据
let res_remove = await collection.limit(1000).orderBy("unix","asc").where({
unix : _.lt(delete_day)
}).remove();
console.log("res_remove",res_remove);
//七牛云的批量删除
let list_img_path_to_delete = [];
for (let item of res.data){
list_img_path_to_delete.push(qiniu.rs.deleteOp(bucket, item._id+".jpg"))
}
let config = new qiniu.conf.Config();
config.zone = qiniu.zone.Zone_z0;
let bucketManager = new qiniu.rs.BucketManager(mac, config);
bucketManager.batch(list_img_path_to_delete, function (err, respBody, respInfo) {
if (err) {
console.log(err);
} else {
//成功后的响应
}
});
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
END
目前在客户端崩溃的时候会做截图上传,后面想想游戏提示断网的时候,也应该弄一个,因为想定位一下到底是什么原因导致的掉线,还有就是,有多少掉线。
题外话:关于云函数的限制和费用
云函数目前有1G/月的免费流量和4万GBs的资源使用量(内存cpu等),超出部分的资费如下:
- 资源使用量(GBs) 0.00011108元
- 外网出流量(GB) 0.8元
还有就是当次请求的超时时间(现在好像是60s),也就是说,一个云函数超过60s,会被强行中断。。。
如果需要在云函数执行一些长耗时的处理怎么办? 为了保证客户端的体验,不允许直接调用长耗时的云函数。
建议在云控制台调整为需要的超时时间(上限为20s),在云函数内使用 callback() 返回成功,客户端不等待执行结果。 云函数会在超时时间内继续执行直到完毕或超时,将执行结果写入数据库等存储服务,再在客户端获取该结果。