今天终于把自己的摄影展示网站发布到了线上。查看网站
这个网站整体并不复杂,但是其中也有不少值得记录的难点,比如从前端上传文件至腾讯云的对象存储,公司业务中我使用过七牛的云存储,腾讯的还从未接触过。本以为应该跟七牛的差不多,但没想到我费了好大的力气各种看文档、看别人的博客才成功上传。
吐槽一句腾讯的文档写的真的好差。
下面分享一下我的上传配置及流程:
整个流程需要前端和后端的配合,所以代码会分为前端代码与后端代码两个部分,下面我会注明。后端我用的是 Node.js。
上传流程说明
上传的整体流程大概是这样:
1、上传前,前端发起请求向服务器发起请求获取上传的临时密钥
2、服务器端收到请求,通过腾讯官方的 sdk 计算出临时密钥并返回给前端
3、前端获取到临时密钥,获取选择的文件,计算 md5 值作为文件名(这样相同文件就不会重复上传)
4、通过官方的 sdk 进行上传,在回调中处理上传后的逻辑
##后端代码 Node.js
基础的服务运行环境我就不做展开了,只讲获取临时密钥的过程。
首先需要安装 qcloud-cos-sts 依赖:
1
| npm install qcloud-cos-sts --save
|
然后就是在你请求的方法文件中编写代码,个人视不同请求而定:
1 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 49 50 51 52 53 54 55 56 57 58 59
|
const STS = require('qcloud-cos-sts');
const config = { secretId: '你的固定密钥', secretKey: '你的固定密钥', proxy: '', durationSeconds: 6000, bucket: 'bucket名字', region: 'bucket 地区', allowPrefix: '*', allowActions: [ 'name/cos:PutObject', 'name/cos:PostObject', 'name/cos:sliceUploadFile', 'name/cos:InitiateMultipartUpload', 'name/cos:ListMultipartUploads', 'name/cos:ListParts', 'name/cos:UploadPart', 'name/cos:CompleteMultipartUpload', ], };
router.get('/upload/sts', (req, res) => { const shortBucketName = config.bucket.substr(0, config.bucket.lastIndexOf('-')); const appId = config.bucket.substr(1 + config.bucket.lastIndexOf('-')); const policy = { version: '2.0', statement: [{ action: config.allowActions, effect: 'allow', principal: { qcs: ['*'] }, resource: [ `qcs::cos:${config.region}:uid/${appId}:prefix//${appId}/${shortBucketName}/${config.allowPrefix}`, ], }], }; STS.getCredential({ secretId: config.secretId, secretKey: config.secretKey, proxy: config.proxy, durationSeconds: config.durationSeconds, policy, }, (err, tempKeys) => { const result = err || tempKeys || ''; res.json(new Result({ data: result })); }); });
|
存储桶的相关信息可以在控制台的存储桶的【概览】中查看。
注意:存储桶所在地域只需括号中的内容,不需要中文。

后端计算临时密钥的方法就是以上这些了。
前端代码
在配置文件中定义好基础信息
1 2 3 4 5 6 7 8
|
export default { Bucket: '', Region: '', Domain: '', };
|
然后安装以下依赖
1
| npm install cos-js-sdk-v5 spark-md5 --save
|
具体上传代码:
1 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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
| import COS from 'cos-js-sdk-v5'; import SparkMD5 from 'spark-md5';
import { sts } from '@/api/upload';
import cosConfig from './cosConf'; let key = '';
const cos = new COS({ async getAuthorization(options, callback) { const res = await sts(); const authdata = res.data; const auth = { TmpSecretId: authdata.credentials.tmpSecretId, TmpSecretKey: authdata.credentials.tmpSecretKey, XCosSecurityToken: authdata.credentials.sessionToken, ExpiredTime: authdata.expiredTime, }; callback(auth); }, FileParallelLimit: 3, ChunkParallelLimit: 8, ChunkSize: 1024 * 1024 * 8, });
function getFileMD5(file, callback) { const fileReader = new FileReader(); const chunkSize = 2 * 1024 * 1024; const chunks = Math.ceil(file.size / chunkSize); let currentChunk = 0;
const spark = new SparkMD5();
fileReader.onload = (e) => { spark.appendBinary(e.target.result); currentChunk += 1;
if (currentChunk < chunks) { loadNext(); } else { callback(spark.end()); } };
function loadNext() { const start = currentChunk * chunkSize; const end = start + chunkSize >= file.size ? file.size : start + chunkSize;
fileReader.readAsBinaryString(file.slice(start, end)); } loadNext(); }
export function uploadFile(file, callback, progressBc) { getFileMD5(file, (md5) => { file.md5 = md5; const subfix = file.name.substr(file.name.lastIndexOf('.')); key = process.env.VUE_APP_BUCKET_PATH + file.md5 + subfix; cos.putObject({ Bucket: cosConfig.Bucket, Region: cosConfig.Region, Key: key, Body: file, onProgress(progressData) { progressBc(progressData.percent); }, }, (err, data) => { callback(err, data); }); }); }
export function uploadFile2(file, callback, progressBc) { getFileMD5(file, (md5) => { file.md5 = md5; const subfix = file.name.substr(file.name.lastIndexOf('.')); key = process.env.VUE_APP_BUCKET_PATH + file.md5 + subfix; cos.sliceUploadFile({ Bucket: cosConfig.Bucket, Region: cosConfig.Region, Key: key, Body: file, onProgress(progressData) { progressBc(progressData.percent); }, }, (err, data) => { callback(err, data); }); }); }
|
调用上传的话,只需这样:
1 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
| <template> <div> <input type="file" accept="image/*" ref="upload" id="upload"> <button @click="submit">上 传</button> </div> </template> <script> import { uploadFile } from '@/utils/uploadfile'; export default { methods: { submit(){ const file = this.$refs.upload.files[0] uploadFile(file, (err, data) => { // 回调 if(!err){ // 上传成功处理 }else{ // 出错处理 } }, progress => { // 这里可以设置上传进度 }); } } } </script>
|
存储桶设置
最后,存储桶还需要设置跨域访问,否则哪怕前面都正确,文件也无法上传。
在存储桶的【安全管理】-【跨域访问CORS设置】中添加规则,设置域名白名单,保存生效后,不出意外就可以正常上传文件了。
