admin管理员组

文章数量:1529463

1. 腾讯云控制台:登录 - 腾讯云

2. 腾讯云对象存储jssdk文档(含cos-js-sdk-v5.min.js文件 + 跨域设置访问配置):对象存储 快速入门-SDK 文档-文档中心-腾讯云33下载与安装相关资源对象存储COS的XMLJSSDK源码下载地址:XMLJavaScriptSDK。SDK快速下载地址:XMLJavaScriptSDK。演示示例Demo下载地址:XMLJavaScrihttps://cloud.tencent/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"
    */
    async getTempCosUploadConfig() {
        const currentAccessHost = window.location.host
        const uploadAapiHostMap = { // 不同域名对于后台接口URL的映射
            'test': 'https://xxx',
            'pre': 'https://xxx',
            'onl': 'https://xxx',
        }
        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/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://wwwblogs/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

 四、参考链接

  • JavaScript中的Error错误对象与自定义错误类型_前端江湖的博客-CSDN博客

本文标签: 腾讯图片视频webcos