1. 腾讯云控制台:登录 - 腾讯云
2. 腾讯云对象存储jssdk文档(含cos-js-sdk-v5.min.js文件 + 跨域设置访问配置):对象存储 快速入门-SDK 文档-文档中心-腾讯云33下载与安装相关资源对象存储COS的XMLJSSDK源码下载地址:XMLJavaScriptSDK。SDK快速下载地址:XMLJavaScriptSDK。演示示例Demo下载地址:XMLJavaScrihttps://cloud.tencent.com/document/product/436/11459
1. JavaScript SDK 常见问题: 对象存储 JavaScript SDK 常见问题-SDK 文档-文档中心-腾讯云
一、封装cos工具函数(类)
class CosUtil {
uploadConfigInfo = {} // cos相关临时密钥等配置信息{ bucket, host, allow_prefix, xxx }
cosInstance = null // cos实例
constructor() {
this.init()
}
init() {
this.getTempCosUploadConfig()
}
/**
* @method 获取COS的临时密钥配置信息
* @return { { allow_prefix, host, bucket, credentials, xxx } } 注意:allow_prefix,存放的目录前缀名,最后是带有斜杠的,如:"web_xx/xx/", host: "https://xxx.xx.com"
*/
async getTempCosUploadConfig() {
const currentAccessHost = window.location.host
const uploadAapiHostMap = { // 不同域名对于后台接口URL的映射
'test.com': 'https://xxx.com',
'pre.com': 'https://xxx.com',
'onl.com': 'https://xxx.com',
}
const currentApiHost = uploadAapiHostMap[currentAccessHost]
const applicationHeaders = { appId: xxx, appKey: 'xxxx' } // 本公司后台接口需要,用于区分不同上传方式。如:web还是app等
const params = { client_type: 'xx', app_name: 'xxx'}
const res = await service({ // service函数是公司内部封装的axios请求方法
headers: applicationHeaders,
url: currentApiHost + '/xx/xxx/getTempKeys',
method: 'post',
data: params
})
this.uploadConfigInfo = res.data
this.getCosInstance()
}
// 获取COS实例
getCosInstance() {
const that = this
// 初始化COS实例
this.cosInstance = new COS({
// getAuthorization 必选参数
getAuthorization: function (options, callback) {
const { start_time, expired_time, credentials } = that.uploadConfigInfo
callback({
TmpSecretId: credentials.tmp_secret_id,
TmpSecretKey: credentials.tmp_secret_key,
SecurityToken: credentials.session_token,
// 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
StartTime: start_time, // 时间戳,单位秒,如:1580000000
ExpiredTime: expired_time, // 时间戳,单位秒,如:1580000000
});
}
});
}
/**
* 上传图片或视频
* @param { String } storePath 文件存放路径 - 注意:开头不要带斜杠/, 直接是文件名,或目录名/xx/文件名
* @param { File } file 文件对象
* @param { Element } progressDom dom对象 - 页面上需要实时显示上传进度的dom元素,选填
*/
handleUploadFile(storePath, file, progressDom) {
const that = this
return new Promise((resolve, reject) => {
const { bucket, region, allow_prefix } = that.uploadConfigInfo
const fullStorePath = allow_prefix + storePath
that.cosInstance.uploadFile({
Bucket: bucket, /* 填写自己的bucket,必须字段 */
Region: region, /* 存储桶所在地域,必须字段 */
Key: fullStorePath, /* 存储在桶里的对象键(例如:1.jpg,a/b/test.txt,图片.jpg)支持中文,必须字段 */
Body: file, // 上传文件对象
SliceSize: 1024 * 1024 * 5, /* 触发分块上传的阈值,超过5MB使用分块上传,小于5MB使用简单上传。可自行设置,非必须 */
onProgress: function(progressData) {
const { percent } = progressData // percent取值:是0-1之间的含小数,如0.55。
progressDom && (progressDom.innerHTML = percent * 100)
},
onFileFinish: function (err, data, options) { /* 非必须 */
console.log(options.Key + '上传' + (err ? '失败' : '完成')); // 如:web_xx/xx/xx/test.1675235009017.png上传失败
},
}, function(err, data = {}) {
if (err) {
console.log('上传失败', Object.prototype.toString.call(err), err.message, data)
that.handleCOSCallFail(err.message)
reject(err)
} else {
console.log('上传成功', data, fullStorePath)
resolve({ ...data, filePath: fullStorePath }) // 如: { statusCode: 200, Location: "xxx-test-1314993711.cos.ap-shanghai.myqcloud.com/web_xx/xpx/xxx/test.1675245328509.png", filePath: "web_xx/xxx/xxx/test.1675245328509.png" }
}
});
})
}
// 处理页面停留过长再操作时,配置会失效的问题
handleCOSCallFail(errMessage = '') {
const configExpiredText = 'Request has expired';
console.log('校验报错信息中是否含配置过期标志', errMessage.indexOf(configExpiredText))
if (errMessage.indexOf(configExpiredText) > -1) {
const confirmResult = window.confirm('COS配置信息已失效, 需要刷新页面!您确定要刷新该页面吗?')
if (confirmResult == true) {
window.location.reload() // 手动刷新页面,重新获取密钥
}
} else {
alert(errMessage)
}
}
/**
* @method 删除文件
* @param { String } storePath 文件存放路径 - 注意:开头不要带斜杠/, 直接是文件名,或目录名/xx/文件名
*/
handleDeleteFile(storePath) {
const that = this
return new Promise((resolve, reject) => {
const { bucket, region, allow_prefix } = that.uploadConfigInfo
const fullStorePath = allow_prefix + storePath
that.cosInstance.deleteObject({
Bucket: bucket, /* 填写自己的bucket,必须字段 */
Region: region, /* 存储桶所在地域,必须字段 */
Key: fullStorePath, /* 存储在桶里的对象键(例如1.jpg,a/b/test.txt),必须字段 */
}, function(err, data) {
if(err) {
console.log('删除文件失败', Object.prototype.toString.call(err), err.message, data)
that.handleCOSCallFail(err.message)
reject(err)
} else {
resolve(data)
}
});
})
}
}
二、在html中使用
小提示:第一次上传到cos某个目录(存储桶bucket下的某个自建目录)时,如果没有手动提前在cos后台创建该目录时,第一次代码上传时,cos后台会自动创建对应目录。
<!-- 引入腾讯云cos的sdk(官网文件,下载到本地引入) -->
<script src="js/cos-js-sdk-v5.min.js"></script>
<script type="text/javascript" src="js/cos-utils.js"></script>
<script language="JavaScript">
var cosClientObj = new CosUtil()
console.log('实例化的cos工具对象', cosClientObj, cosClientObj.handleUploadFile)
</script>
old实现方式如下(含:cookie缓存临时密钥,过期后自动重新获取逻辑):未封装成类,复用性差!
一、在.html中使用cos
<!-- 引入腾讯云cos的sdk(官网下载到本地) -->
<script src="js/cos-js-sdk-v5.min.js"></script>
... // 省略code
<script type="module" language="JavaScript">
import { Cookie } from '/xxx/js/utils.js'
const webUploadCookieKey = 'xpx_web_upload_config'
const applicationHeaders = { appId: xxx, appKey: 'xxx' } // 后台需要的传参
let uploadConfigInfo = {}
$(document).ready(function() {
const uploadConfig = Cookie.get(webUploadCookieKey)
if (uploadConfig) {
uploadConfigInfo = JSON.parse(uploadConfig) || {}
const isExpired = getCurrentSecondUnitOfTimeStamp() >= uploadConfigInfo.expired_time
console.log('腾讯云cos临时密钥是否过期', isExpired, uploadConfigInfo)
if (isExpired) {
getTempCosUploadConfig()
}
} else {
getTempCosUploadConfig()
}
});
// 获取当前时间戳(秒级)
function getCurrentSecondUnitOfTimeStamp () {
return Date.parse(new Date() + '') / 1000
}
// 初始化COS实例
var cos = new COS({
// getAuthorization 必选参数
getAuthorization: function (options, callback) {
const { start_time, expired_time, credentials } = uploadConfigInfo
callback({
TmpSecretId: credentials.tmp_secret_id,
TmpSecretKey: credentials.tmp_secret_key,
SecurityToken: credentials.session_token,
// 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
StartTime: start_time, // 时间戳,单位秒,如:1580000000
ExpiredTime: expired_time, // 时间戳,单位秒,如:1580000000
});
}
});
// 调后台接口:获取COS上传临时密钥的配置信息
async function getTempCosUploadConfig() {
const params = { client_type: 'web', app_name: 'xxx'}
const res = await service({ // 封装的axios请求
headers: applicationHeaders,
url: currentApiHost + '/xxx/upload/getTempKeys',
method: 'post',
data: params
})
const { expired_time } = res.data
const validSecond = expired_time - getCurrentSecondUnitOfTimeStamp()
Cookie.set(webUploadCookieKey, JSON.stringify(res.data), { maxAge: validSecond })
uploadConfigInfo = res.data
}
// 上传图片&视频
function handleFileInUploading(fileName, file, progressDom, goodsId) {
return new Promise((resolve, reject) => {
const { bucket, region, allow_prefix } = uploadConfigInfo
const uploadKey = goodsId ? `${allow_prefix}goodsVideos/${goodsId}-${fileName}` : (`${allow_prefix}goodsImages/${fileName}`)
cos.uploadFile({
Bucket: bucket, /* 填写自己的bucket,必须字段 */
Region: region, /* 存储桶所在地域,必须字段 */
Key: uploadKey, /* 存储在桶里的对象键(例如:1.jpg,a/b/test.txt,图片.jpg)支持中文,必须字段 */
Body: file, // 上传文件对象
SliceSize: 1024 * 1024 * 5, /* 触发分块上传的阈值,超过5MB使用分块上传,小于5MB使用简单上传。可自行设置,非必须 */
onProgress: function(progressData) {
console.log('上传文件进度为:', JSON.stringify(progressData));
const { percent } = progressData // percent取值:是0-1之间的含小数,如0.55。
progressDom && (progressDom.innerHTML = percent * 100)
},
onFileFinish: function (err, data, options) { /* 非必须 */
console.log(options.Key + '上传' + (err ? '失败' : '完成'));
},
}, function(err, data) {
console.log('上传的结果是:', err, data)
if (err) {
console.log('上传失败', err);
handleCOSFail(err.message)
reject(err)
} else {
// 注意:返回的Location字段就是文件的ulr,但是没有'http(s)://'头,需自己手动加。
console.log('上传成功', err, data); // null, { Location:'test-xx/xx/.png', ... }
resolve(data)
}
});
})
}
// 处理页面停留过长再操作时,配置会失效的问题 & 提示其他报错信息
function handleCOSFail(errMessage) {
const configExpiredText = 'Request has expired';
if (errMessage.indexOf(configExpiredText) > -1) {
const confirmResult = window.confirm('COS配置信息已失效, 需要刷新页面!您确定要刷新该页面吗?')
if (confirmResult == true) {
Cookie.remove(webUploadCookieKey)
window.location.reload() // 手动刷新页面,重新获取密钥
}
} else {
alert(errMessage)
}
}
// 删除已上传的文件
function handleDeleteUploadedFile(goodsId, fileName) {
return new Promise((resolve, reject) => {
const { bucket, region, allow_prefix } = uploadConfigInfo
const uploadKey = goodsId ? `${allow_prefix}goodsVideos/${goodsId}-${fileName}` : (`${allow_prefix}goodsImages/${fileName}`)
cos.deleteObject({
Bucket: bucket, /* 填写自己的bucket,必须字段 */
Region: region, /* 存储桶所在地域,必须字段 */
Key: uploadKey, /* 存储在桶里的对象键(例如1.jpg,a/b/test.txt),必须字段 */
}, function(err, data) {
console.log(err || data);
if(err) {
console.log('删除文件失败', err)
handleCOSFail(err.message)
reject(err)
} else {
console.log('删除文件成功', data) // {statusCode: 204, ... }
resolve(data)
}
});
})
}
二、工具函数cookie封装(设置、获取、删除)
// utils.js文件
export const Cookie = {
/** 设置cookie
* @Params { key, value, options } // 如:setCookie('token', 'xxxx', { maxAge: 24 * 60 * 60 })
* @Note 1. options参数:maxAge(单位是秒,即多少秒后cookie过期)、path、secret、expires
* @Note 2. 客户端设置domain是无效的,因为只能是当前域
* @Note 3. 设置cookie的存储值为对象时,需先JSON.stringify(obj)。
* @Docuement https://www.cnblogs.com/yesyes/p/15352703.html
*/
set: function (key, value, options) {
// 注意:encodeURIComponent(str) 是用来编码, 获取cookie时,需使用decodeURIComponent(str)解码
let cookie = encodeURIComponent(key) + '=' + encodeURIComponent(value) + '; ';
for(let k in options) {
// 首字母大写,驼峰转下换线
const newkey = k.replace(/^\S/, function($1) {
return $1.toUpperCase();
}).replace(/\B[A-Z]/g,function($1) {
return '-' + $1
})
if(newkey === 'Secure') {
cookie += 'Secure; '
}else{
cookie += newkey +'=' + options[k] + '; '
}
}
document.cookie = cookie
},
get: function (cookieKey) {
if (document.cookie.length > 0) {
var arr = document.cookie.split('; ') // 这里显示的格式需要切割一下自己可输出看下
for (let i = 0; i < arr.length; i++) {
let arr2 = arr[i].split('=') // 再次切割
// 判断查找相对应的值
if (arr2[0] === cookieKey) {
return decodeURIComponent(arr2[1]) // 需要先解码,再返回。
}
}
}
},
remove: function(cookieKey) {
Cookie.set(cookieKey, '', { maxAge: 0 }); // 删除指定的cookie
}
};
三、项目中遇到的问题&解决
1、调用cos的deleteObject()方法时,报错提示:Access Denied。
答:因公司后台接口返回的临时密钥(使用子账号生成的),没有配置删除的权限( "name/cos:DeleteObject")导致。具体参考:腾讯COS – 使用临时密钥下载私有桶对象失败Cos Error Code: AccessDenied【踩坑】 – foam