官网地址
:
对象存储 uni-app 直传实践-最佳实践-文档中心-腾讯云
https://github.com/tencentyun/cos-demo/blob/main/server/post-policy/nodejs/app.js
官方给出的直传解决方案:前端 + 服务端nodejs
这里将服务端nodejs改为js格式,自己处理数据实现直传
1. 获取COS上传文件需要用到的数据
前端要使用COS上传文件,需要提前从后端获取到
TmpSecretId:临时密钥的 tmpSecretId
TmpSecretKey:临时密钥的 tmpSecretKey
SecurityToken:临时密钥的 sessionToken,对应 header 的 x-cos-security-token 字段
ExpiredTime:<可选>临时密钥的 expiredTime,超时时刻的时间戳(也可以前端自己定义)
Bucket:自己的bucket桶名称
Region:存储桶所在地域
根据自己项目的接口调用方法,调用后端接口,获取到上述数据
2. 直传数据解析(根据官网nodejs修改而来)
安装crypto-js依赖:
npm install crypto-js
// 临时密钥服务例子
var crypto = require("crypto-js");
/**
*
* @param {*} file 文件
* @param {string} fileName 文件名,例如:'1.jpg'或'test.txt'
* @param {object} config COS直传解析参数{TmpSecretId, TmpSecretId, SecurityToken, Bucket, region}
* @returns
*/
export const handelPostPolice = (file, fileName, config) => {
const nowTime = new Date();
// 开始计算凭证
var cosHost = `${config.bucket_name}.cos.${config.region}.myqcloud.com`;
var cosKey = `${nowTime.getFullYear()}-${nowTime.getMonth() + 1}/${new Date().getTime()}${fileName.split('/').pop()}`; /* 上传后的文件在桶中的位置,如果想要放在text文件下,可以定义为text/文件名。文件地址可以前端自己定义,也可以后端返回。 */
var now = Math.round(Date.now() / 1000);
var exp = now + 900;
var qKeyTime = now + ';' + exp;
// 生成上传要用的 policy
var policy = JSON.stringify({
'expiration': new Date(exp * 1000).toISOString(),
'conditions': [
{'q-sign-algorithm': 'sha1'},
{'q-ak': config.access_key_id},
{'q-sign-time': qKeyTime},
{'bucket': config.bucket_name},
{'key': cosKey},
]
});
// 步骤一:生成 SignKey
var signKey = crypto.HmacSHA1(qKeyTime, config.access_key_secret).toString(crypto.enc.Hex);
// 步骤二:生成 StringToSign
var stringToSign = crypto.SHA1(policy).toString(crypto.enc.Hex);
// 步骤三:生成 Signature
var qSignature = crypto.HmacSHA1(stringToSign, signKey).toString(crypto.enc.Hex);
var data = {
cosHost: cosHost,
cosKey: cosKey,
policy: Buffer.from(policy).toString('base64'),
qAk: config.access_key_id,
qKeyTime: qKeyTime,
qSignature: qSignature,
}
return data
}
3. 封装uni-app直传方法
import { handelPostPolice } from './handelPostPolice.js' // 引入直传数据解析方法
const nowTime = new Date();
/**
*
* @param {*} file 文件
* @param {string} fileName 文件名,例如:'1.jpg'或'test.txt'
* @param {object} res COS上传参数{TmpSecretId, TmpSecretId, SecurityToken, Bucket, region}
* @returns
*/
export const uploadFileOrPic = (file, fileName, res) => {
// COS上传数据 转 直传数据
let opt = handelPostPolice(file, fileName, res)
// 上传图片
return new Promise((resolve, reject) => {
console.log('COS图片上传', opt.cosKey)
var formData = {
key: opt.cosKey,
policy: opt.policy, // 这个传 policy 的 base64 字符串
success_action_status: 200,
'q-sign-algorithm': 'sha1',
'q-ak': opt.qAk,
'q-key-time': opt.qKeyTime,
'q-signature': opt.qSignature,
};
uni.uploadFile({
url: 'https://' + opt.cosHost, // 腾讯云服务器地址
filePath: file, //本地上传文件路径
name: 'file',
formData: formData,
success: (res) => {
var fileUrl = 'https://' + opt.cosHost + '/' + camSafeUrlEncode(opt.cosKey).replace(/%2F/g, '/');
resolve(fileUrl);
},
error(err) {
reject(err);
},
});
});
};
// 对更多字符编码的 url encode 格式
const camSafeUrlEncode = function (str) {
return encodeURIComponent(str)
.replace(/!/g, '%21')
.replace(/'/g, '%27')
.replace(/\(/g, '%28')
.replace(/\)/g, '%29')
.replace(/\*/g, '%2A');
};
4. 文件上传
<template>
<view>
<uni-file-picker ref="file" v-model="imgUrl" fileMediatype="image" mode="grid" @select="select" :sizeType="sizeType"></uni-file-picker>
</view>
</template>
<script>
import { uploadFileOrPic } from "@/common/uploadFile.js"
export default {
data() {
return {
imgUrl: null,
sizeType: ['compressed'], //设置图片压缩
}
},
methods: {
// 获取上传状态
async select(e) {
let flieArr = e.tempFiles
for (let i = 0; i < flieArr.length; i++) {
// 获取图片信息
let file = flieArr[i].path;
// 调用接口获取文件上传信息
const res = await this.$request(cosKey, "post");
// 文件上传
let _this = this;
uploadFileOrPic(file, file, res).then(url => {
_this.imgUrl = url
})
}
}
}
}
</script>