1.背景
时间碎片化是现代社会中一个普遍存在的问题,它给人们的生活和工作带来了许多挑战。
首先,时间碎片化导致了人们难以集中精力完成任务。在不断切换不同任务和应用程序的过程中,人们的注意力不断被分散,导致难以保持专注和高效。这不仅影响了工作效率,还可能导致工作质量下降。
其次,时间碎片化可能导致人们的压力和焦虑感增加。当人们感到自己的时间被切割成许多小块,无法掌控自己的生活和工作时,他们可能会感到不安和焦虑。这种情绪状态可能对人们的身心健康产生负面影响。
此外,时间碎片化还可能影响人们的创造力和思考能力。由于时间被分割成小块,人们可能没有足够的时间和空间进行深入的思考和创造性的工作。这可能会限制人们的创新能力和发展潜力。
然而,我们也要认识到时间碎片化是现代社会中不可避免的现象。随着科技的发展和生活节奏的加快,人们需要处理的信息和任务越来越多,时间碎片化也在所难免。因此,我们应该寻找有效的方法来应对时间碎片化带来的挑战。
为此,我们开发了一款数学益智应用--无聊数学。如果你感兴趣,可以直接微信打开。
同时,我们主张:
用数学打发无聊时间
2.问题的产生
在无聊数学中,用户可以提交自己的创意题目,也可以更新自己的图片,用户会上传图片,为了减少服务器的压力,我们设计上让app直接把图片上传到腾讯云的对象云存储COS,同时,也让整体技术方案更加简便。
3.如何解决问题
3.1 关于腾讯云对象云存储COS
对象存储(Cloud Object Storage,COS)是腾讯云提供的一种存储海量文件的分布式存储服务,用户可通过网络随时存储和查看数据。腾讯云 COS 使所有用户都能使用具备高扩展性、低成本、可靠和安全的数据存储服务。
COS 通过控制台、API、SDK 和工具等多样化方式简单、快速地接入,实现了海量数据存储和管理。通过 COS 可以进行任意格式文件的上传、下载和管理。腾讯云提供了直观的 Web 管理界面,同时遍布全国范围的 CDN/EdgeOne 节点可以对文件下载进行加速。
如果你的应用需要使用到对象存储,更多的细节,你可以访问腾讯云的对象云存储COS。
3.2前端直传的过程
前端直传,本质就是向服务端发送一个PUT Object的请求,例如,以下就是最简单的Put Object请求:
PUT /exampleobject HTTP/1.1
Host: examplebucket-1250000000.cos.ap-beijing.myqcloud.com
Date: Fri, 10 Apr 2020 09:35:05 GMT
Content-Type: image/jpeg
Content-Length: 16
Content-MD5: 7o3pGNBWQBRbGPcPTDqmAg==
Authorization: q-sign-algorithm=sha1&q-ak=AKID8A0fBVtYFrNm02oY1g1JQQF0c3JO****&q-sign-time=1586511305;1586518505&q-key-time=1586511305;1586518505&q-header-list=content-length;content-md5;content-type;date;host&q-url-param-list=&q-signature=c4147d4d457869a49b13e8e936c06a12c809****
Connection: close
[Object Content]
向COS服务端发送一个Put Object的主要过程,分为两个步骤:
- 实现一个服务端接口,用于生成随机文件路径、计算签名,并返回给前端
- 前端直接发起upload的请求
3.3 服务器端计算签名
以下的例子就是一个serverless版本的云函数,在服务端已经运行通过。
const crypto = require('crypto');
const moment = require('moment');
let myHandler = async function (event, context, callback, logger) {
logger.info(event);
const ext = event.extName;
// 配置参数
var config = {
// 获取腾讯云密钥,建议使用限定权限的子用户的密钥 https://console.cloud.tencent.com/cam/capi
secretId: secretId,
secretKey: secretKey,
// 这里填写存储桶、地域,例如:test-1250000000、ap-guangzhou
bucket: 'wuliaoshuxue-xx',
region: 'ap-xxx',
// 限制的上传后缀
extWhiteList: ['jpg', 'jpeg', 'png', 'gif', 'bmp'],
};
// 生成要上传的 COS 文件路径文件名
var generateCosKey = function (ext) {
var ymd = moment().format('YYYYMMDD_HHmmss');
var r1 = ('000000' + Math.random() * 1000000).slice(-6);
var r2 = ('000000' + Math.random() * 1000000).slice(-6);
var cosKey = `collect-question/${ymd}_${r1}_${r2}.${ext}`;
return cosKey;
};
// 判断异常情况
if (!config.secretId || !config.secretKey){
}
if (!config.bucket || !config.region){
}
if (!config.extWhiteList.includes(ext)){
}
// 开始计算凭证
var cosHost = `${config.bucket}.cos.${config.region}.myqcloud.com`;
var cosKey = generateCosKey(ext);
var now = Math.round(Date.now() / 1000);
var exp = now + 900;
var qKeyTime = now + ';' + exp;
var qSignAlgorithm = 'sha1';
// 生成上传要用的 policy
// PostObject 签名保护文档 https://cloud.tencent.com/document/product/436/14690#.E7.AD.BE.E5.90.8D.E4.BF.9D.E6.8A.A4
var policy = JSON.stringify({
'expiration': new Date(exp * 1000).toISOString(),
'conditions': [
// {'acl': query.ACL},
// ['starts-with', '$Content-Type', 'image/'],
// ['starts-with', '$success_action_redirect', redirectUrl],
// ['eq', '$x-cos-server-side-encryption', 'AES256'],
{'q-sign-algorithm': qSignAlgorithm},
{'q-ak': config.secretId},
{'q-sign-time': qKeyTime},
{'bucket': config.bucket},
{'key': cosKey},
]
});
// 步骤一:生成 SignKey
var signKey = crypto.createHmac('sha1', config.secretKey).update(qKeyTime).digest('hex');
// 步骤二:生成 StringToSign
var stringToSign = crypto.createHash('sha1').update(policy).digest('hex');
// 步骤三:生成 Signature
var qSignature = crypto.createHmac('sha1', signKey).update(stringToSign).digest('hex');
const result = {
cosHost: cosHost,
cosKey: cosKey,
policy: Buffer.from(policy).toString('base64'),
qSignAlgorithm: qSignAlgorithm,
qAk: config.secretId,
qKeyTime: qKeyTime,
qSignature: qSignature,
// securityToken: securityToken, // 如果 SecretId、SecretKey 是临时密钥,要返回对应的 sessionToken 的值
};
callback({
code : 0,
msg: 'success',
result : result
});
};
export { myHandler };
3.4 App端的操作
app端从调用云函数获取凭证之后,以下的代码就是发起put请求了。
function getUploadUrl(opt){
// 对更多字符编码的 url encode 格式
var camSafeUrlEncode = function(str) {
return encodeURIComponent(str)
.replace(/!/g, '%21')
.replace(/'/g, '%27')
.replace(/\(/g, '%28')
.replace(/\)/g, '%29')
.replace(/\*/g, '%2A');
};
var fileUrl = 'https://' + opt.cosHost + '/' + camSafeUrlEncode(opt.cosKey).replace(/%2F/g,
'/');
return fileUrl;
}
async function upload(filePath, opt, callback) {
var vm = this;
var formData = {
key: opt.cosKey,
policy: opt.policy, // 这个传 policy 的 base64 字符串
success_action_status: 200,
'q-sign-algorithm': opt.qSignAlgorithm,
'q-ak': opt.qAk,
'q-key-time': opt.qKeyTime,
'q-signature': opt.qSignature,
};
if (opt.securityToken) {
formData['x-cos-security-token'] = formData.securityToken;
}
uni.uploadFile({
url: 'https://' + opt.cosHost, //仅为示例,非真实的接口地址
filePath: filePath,
name: 'file',
formData: formData,
success: (res) => {
console.log("uni.uploadFile success res: ", res);
if (![200, 204].includes(res.statusCode)) return callback && callback(res);
var fileUrl = getUploadUrl(opt);
callback && callback(null, fileUrl);
},
error(err) {
console.log("uni.uploadFile err : ", err);
//
callback && callback(err);
},
});
}
4.总结
本文描述了如何从前端直接发起PUT Object请求,将文件上传到腾讯云的对象云存储COS,不同的项目,具体情况不同,如要依据实际的情况选择不同的文件上传方案。
5.无聊数学系列文章
无聊数学是我们开发的一款数字益智应用,本系列文章,都是介绍相关的移动开发技术以及服务端开端技术,如果你感兴趣,欢迎继续阅读。