前端使用js控制腾讯云cos存储对象,优化静态文件存储读取的功能,获取预签名,上传下载,腾讯云大文件分块上传失败,报错跨域失败

一、对象存储是什么?

对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。COS 提供网页端管理界面、多种主流开发语言的 SDK、API 以及命令行和图形化工具,并且兼容 S3 的 API 接口,方便用户直接使用社区工具和插件。

二、使用步骤

1.引入库

代码如下(示例):

npm i cos-js-sdk-v5 --save

2.引入作为模块

代码如下(示例):

var COS = require('cos-js-sdk-v5');

3.前端使用固定密钥计算签名,该格式适用于前端调试

代码如下(示例):

var cos = new COS({
    SecretId: 'COS_SECRETID',
    SecretKey: 'COS_SECRETKEY',
});

4.下载对象

代码如下(示例):

cos.getObject({
    Bucket: 'examplebucket-1250000000', /* 必须 */
    Region: 'COS_REGION',     /* 存储桶所在地域,必须字段 */
    Key: 'exampleobject',              /* 必须 */
}, function(err, data) {
    console.log(err || data.Body);
});

5.上传对象

代码如下(示例):

cos.putObject({
    Bucket: 'examplebucket-1250000000', /* 必须 */
    Region: 'COS_REGION',     /* 存储桶所在地域,必须字段 */
    Key: 'exampleobject',              /* 必须 */
    StorageClass: 'STANDARD',
    Body: fileObject, // 上传文件对象
    onProgress: function(progressData) {
        console.log(JSON.stringify(progressData));
    }
}, function(err, data) {
    console.log(err || data);
});

6.调用cos上传下载跨域

将腾讯云的桶基本配置修改
添加跨域访问CORS规则
在这里插入图片描述

7.获取预签名,获取对象下载的鉴权凭证

COS XML API 的请求里,私有资源操作都需要鉴权凭证 Authorization,用于判断当前请求是否合法。

鉴权凭证使用方式有两种:

放在 header 参数里使用,字段名:authorization。
放在 url 参数里使用,字段名:sign。
COS.getAuthorization 方法用于计算鉴权凭证(Authorization),用以验证请求合法性的签名信息。

代码如下(示例):

Sign: false, //不需要预签名的时候
var cos = new COS({
getAuthorization: function(options, callback) { 
    // var authorization = COS.getAuthorization({
    //     // SecretId: 'AKIDMjxwd4S9pFQKzNfVEjyxg9LQE8nAnCpC',
    //     // SecretKey: 'mHqAHNFrDQ2Vki028yf5FD0XZeUAbnjT',
    //     SecretId: tmpSecretId,
    //     SecretKey: tmpSecretKey,
    //     Token: sessionToken,
    //            Method: options.Method,
    //            Key: options.Key,
    //            Query: options.Query,
    //            Headers: options.Headers,
    //            Expires: 60,
    // });
    // callback(authorization);
    callback({
        TmpSecretId: tmpSecretId,
        TmpSecretKey: tmpSecretKey,
        XCosSecurityToken: sessionToken,
        // 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
        StartTime: result.startTime, // 时间戳,单位秒,如:1580000000
        ExpiredTime: result.expiredTime, // 时间戳,单位秒,如:1580000900
    });
}
});

8.获取预签名,上传文件,真正意义上的减轻服务器压力

代码如下(示例):

var cos = new COS({
getAuthorization: function(options, callback) { 
    // var authorization = COS.getAuthorization({
    //     // SecretId: 'AKIDMjxwd4S9pFQKzNfVEjyxg9LQE8nAnCpC',
    //     // SecretKey: 'mHqAHNFrDQ2Vki028yf5FD0XZeUAbnjT',
    //     SecretId: tmpSecretId,
    //     SecretKey: tmpSecretKey,
    //     Token: sessionToken,
    //            Method: options.Method,
    //            Key: options.Key,
    //            Query: options.Query,
    //            Headers: options.Headers,
    //            Expires: 60,
    // });
    // callback(authorization);
    callback({
        TmpSecretId: tmpSecretId,
        TmpSecretKey: tmpSecretKey,
        XCosSecurityToken: sessionToken,
        // 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
        StartTime: result.startTime, // 时间戳,单位秒,如:1580000000
        ExpiredTime: result.expiredTime, // 时间戳,单位秒,如:1580000900
    });
}
});

9.操作存储对象的时候,http请求报错403

http请求报错详解链接: https://blog.csdn.net/qq_43305958/article/details/108422927.

403报错是权限不够,改桶和文件夹的权限,改为以下的公共读私有写权限
在这里插入图片描述

10.大文件分块上传失败

使用cos的uploadFiles方法可以上传多个文件,同时在上传大文件的时候会自动分块上传,每个文件都有固定编号,在上传成功后在cos桶中合并
官方建议
分块上传最多支持将较大的对象切分为10000个分块,切分的分块大小范围一般为1MB - 5GB,最后一个分块可以小于1MB
简单上传的方式只支持最大5GB的文件上传,而通过分块上传的方式可上传大于5GB的文件。
个人建议
没有5G以上的文件上传吧

cos.uploadFiles({
files: [{
    Bucket: _that.bucketName /* 必须 */ ,
    Region: _that.Region /* 存储桶所在地域,必须字段 */ ,
    Key: allUrl /* 必须 */ ,
    Body: fileObject,
    Sign: true
}],
// Bucket: _that.bucketName /* 必须 */ ,
// Region: _that.Region /* 存储桶所在地域,必须字段 */ ,
// Key: allUrl /* 必须 */ ,
// Body: fileObject,
onProgress: function(info) {
    var percent = parseInt(info.percent * 10000) / 100;
    var speed = parseInt(info.speed / 1024 / 1024 * 100) / 100;
    console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;');
},
onFileFinish: function(err, data, options) {
    console.log(options.Key + '上传' + (err ? '失败' : '完成'));
},
}

这是一个80M的文件,前面几次的分块上传正常,突然失败
在这里插入图片描述
在这里插入图片描述
改用cos的putObject方法一次性上传

cos.putObject({
Bucket: _that.bucketName /* 必须 */ ,
Region: _that.Region /* 存储桶所在地域,必须字段 */ ,
Key: allUrl /* 必须 */ ,
Body: fileObject,
onProgress: function(info) {
    var percent = parseInt(info.percent * 10000) / 100;
    var speed = parseInt(info.speed / 1024 / 1024 * 100) / 100;
    console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;');
},
onFileFinish: function(err, data, options) {
    console.log(options.Key + '上传' + (err ? '失败' : '完成'));
},
}

只有一次请求,成功
在这里插入图片描述

在这里插入图片描述

11.使用getObjectUrl后用URL下载文件403

已经使用了预签名,通过了防盗链,获取到了url,如果这个时候是没有防盗链的文件就可以通过url下载,当遇到加上防盗链的文件,就无法用url下载文件,
改用getObject方法,通过防盗链直接下载文件,返回的文件是文件,需要转成blob文件流格式,再将blob转成公用URL格式,创建一个a标签,将url设为a标签src属性,点击下载

cos.getObject({
// Bucket: _that.bucketName /* 必须 */ ,
Bucket: _that.bucketName /* 必须 */ ,
Region: _that.Region /* 存储桶所在地域,必须字段 */ ,
Key: url /* 必须 */ ,
// Sign: false,
// sign: Authorization,
},
function(err, data) {
var blob = new Blob([data.Body]);
let blobUrl = URL.createObjectURL(blob)
if (err) {
    _that.$message.error(err)
    return
}
// 保存到本地并自动点击
function saveAs(data, name) {
    const urlObject = window.URL || window.webkitURL || window;
    const export_blob = new Blob([data]);
    const save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
    save_link.href = urlObject.createObjectURL(export_blob);
    save_link.download = name;
    save_link.click();
    let formData3 = new FormData()
    formData3.append('taskid', id);
    postAction(_that.downloadOver, formData3)
}
// 下载含有url的文件
function downloadUrlFile(url, fileName) {
    const url2 = url.replace(/\\/g, '/');
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url2, true);
    xhr.responseType = 'blob';
    //xhr.setRequestHeader('Authorization', 'Basic a2VybWl0Omtlcm1pdA==');
    // 为了避免大文件影响用户体验,建议加loading
    xhr.onload = () => {
        if (xhr.status === 200) {
            // 获取文件blob数据并保存
            saveAs(xhr.response, fileName);
        }
    };
    xhr.send();
}
downloadUrlFile(blobUrl, name)
}

重点

一个成功的操作cos存储对象上传、多个文件上传、下载 的案例

//导入导出界面的下载调用此方法
createCos(code, url, name, id) {
    var COS = require('cos-js-sdk-v5')
    const formData = new FormData();
    formData.append('modelName', code);
    let _that = this
    if (code === 1) {
        postAction(this.getCosUrl, formData).then((res) => {
            if (res.success) {
                let result = JSON.parse(res.message)
                var cos = new COS({
                        TmpSecretId: result.tmpSecretId,
                        TmpSecretKey: result.tmpSecretKey,
                    })
                    // console.log(_that.bucketName)
                cos.getObjectUrl({
                        // Bucket: _that.bucketName /* 必须 */ ,
                        Bucket: _that.bucketName /* 必须 */ ,
                        Region: _that.Region /* 存储桶所在地域,必须字段 */ ,
                        Key: url /* 必须 */ ,
                        Sign: false,
                        // sign: Authorization,
                    },
                    function(err, data) {
                        if (err) {
                            _that.$message.error(err)
                            return
                        }
                        // 保存到本地并自动点击
                        function saveAs(data, name) {
                            const urlObject = window.URL || window.webkitURL || window;
                            const export_blob = new Blob([data]);
                            const save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
                            save_link.href = urlObject.createObjectURL(export_blob);
                            save_link.download = name;
                            save_link.click();
                            let formData3 = new FormData()
                            formData3.append('taskid', id);
                            postAction(_that.downloadOver, formData3)
                        }
                        // 下载含有url的文件
                        function downloadUrlFile(url, fileName) {
                            const url2 = url.replace(/\\/g, '/');
                            const xhr = new XMLHttpRequest();
                            xhr.open('GET', url2, true);
                            xhr.responseType = 'blob';
                            //xhr.setRequestHeader('Authorization', 'Basic a2VybWl0Omtlcm1pdA==');
                            // 为了避免大文件影响用户体验,建议加loading
                            xhr.onload = () => {
                                if (xhr.status === 200) {
                                    // 获取文件blob数据并保存
                                    saveAs(xhr.response, fileName);
                                }
                            };
                            xhr.send();
                        }
                        downloadUrlFile(data.Url, name)
                    }
                )
            } else {
                this.$message.warning(res.message)
            }
        }, (err) => {
            this.$message.warning(err)
        })
    }
},
//导入文件调用此方法
uploadCos(fileObject, url, code, userid, modal = '') {
    var COS = require('cos-js-sdk-v5'),
        _that = this
    const formData = new FormData();
    if (code === 1) {
        formData.append('modelName', 1);
        let allUrl = this.uploadUrl + userid + '/' + url
        postAction(this.getCosUrl, formData).then((res) => {
            if (res.success) {
                let result = JSON.parse(res.message)
                let tmpSecretId = result.credentials.tmpSecretId,
                    tmpSecretKey = result.credentials.tmpSecretKey,
                    sessionToken = result.credentials.sessionToken
                var cos = new COS({
                    getAuthorization: function(options, callback) { 
                        callback({
                            TmpSecretId: tmpSecretId,
                            TmpSecretKey: tmpSecretKey,
                            XCosSecurityToken: sessionToken,
                            // 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
                            StartTime: result.startTime, // 时间戳,单位秒,如:1580000000
                            ExpiredTime: result.expiredTime, // 时间戳,单位秒,如:1580000900
                        });
                    }
                });
                cos.putObject({
                    Bucket: _that.bucketName /* 必须 */ ,
                    Region: _that.Region /* 存储桶所在地域,必须字段 */ ,
                    Key: allUrl /* 必须 */ ,
                    Body: fileObject,
                    onProgress: function(info) {
                        var percent = parseInt(info.percent * 10000) / 100;
                        var speed = parseInt(info.speed / 1024 / 1024 * 100) / 100;
                        console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;');
                    },
                    onFileFinish: function(err, data, options) {
                        console.log(options.Key + '上传' + (err ? '失败' : '完成'));
                    },
                }, function(err, data) {
                    let status = err ? 500 : 200
                    if (status == 200) {
                        const formData2 = new FormData();
                        formData2.append('model', modal);
                        formData2.append('key', url);
                        postAction(_that.cosTask, formData2).then(res => {
                            _that.uploadResult = res
                        }, err => {
                            let res = Object.assign({}, {
                                message: "执行失败",
                                success: false
                            })
                            _that.uploadResult = res
                        })
                    } else {
                        let res = Object.assign({}, {
                            message: "执行失败",
                            success: false
                        })
                        _that.uploadResult = res
                    }
                });
            } else {
                this.$message.warning(res.message)
            }
        }, (err) => {
            let res = Object.assign({}, {
                message: "执行失败",
                success: false
            })
            _that.uploadResult = res
            this.$message.warning(err)
        })

    } else if (code === 0) {
        formData.append('modelName', 2);
        postAction(this.getCosUrl, formData).then((res) => {
            if (res.success) {
                let result = JSON.parse(res.message)
                let tmpSecretId = result.credentials.tmpSecretId,
                    tmpSecretKey = result.credentials.tmpSecretKey,
                    sessionToken = result.credentials.sessionToken
                var cos = new COS({
                    getAuthorization: function(options, callback) { 
                        // var authorization = COS.getAuthorization({
                        //     // SecretId: 'AKIDMjxwd4S9pFQKzNfVEjyxg9LQE8nAnCpC',
                        //     // SecretKey: 'mHqAHNFrDQ2Vki028yf5FD0XZeUAbnjT',
                        //     SecretId: tmpSecretId,
                        //     SecretKey: tmpSecretKey,
                        //     Token: sessionToken,
                        //            Method: options.Method,
                        //            Key: options.Key,
                        //            Query: options.Query,
                        //            Headers: options.Headers,
                        //            Expires: 60,
                        // });
                        // callback(authorization);
                        callback({
                            TmpSecretId: tmpSecretId,
                            TmpSecretKey: tmpSecretKey,
                            XCosSecurityToken: sessionToken,
                            // 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
                            StartTime: result.startTime, // 时间戳,单位秒,如:1580000000
                            ExpiredTime: result.expiredTime, // 时间戳,单位秒,如:1580000900
                        });
                    }
                });
                cos.uploadFiles({
                    files: [{
                        Bucket: _that.bucketName /* 必须 */ ,
                        Region: _that.Region /* 存储桶所在地域,必须字段 */ ,
                        Key: url /* 必须 */ ,
                        Body: fileObject,
                        Sign: true
                    }],
                    SliceSize: 1024 * 1024,
                    onProgress: function(info) {
                        var percent = parseInt(info.percent * 10000) / 100;
                        var speed = parseInt(info.speed / 1024 / 1024 * 100) / 100;
                        console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;');
                    },
                    onFileFinish: function(err, data, options) {
                        console.log(options.Key + '上传' + (err ? '失败' : '完成'));
                    },
                }, function(err, data) {
                    let status = err ? 500 : 200
                    if (status == 200) {
                        let res = Object.assign({}, {
                            message: "执行成功",
                            success: true
                        })
                        _that.uploadResult = res
                    } else {
                        let res = Object.assign({}, {
                            message: "执行失败",
                            success: false
                        })
                        _that.uploadResult = res
                    }
                });
            } else {
                this.$message.warning(res.message)
            }
        }, (err) => {
            let res = Object.assign({}, {
                message: "执行失败",
                success: false
            })
            _that.uploadResult = res
            this.$message.warning(err)
        })

    }
},
// ? 质量控制上传多张图片
uploadMultipleImages(imageFiles, urls, details) {
    const formData = new FormData();
    formData.append('modelName', 2);
    const COS = require('cos-js-sdk-v5')
    const _that = this
        // const formData = new FormData();
        // formData.append('modelName', code);
    let files = []
    imageFiles.forEach((item, index) => {
            // let timestamp = new Date().valueOf()
            files.push({
                Bucket: this.bucketName /* 必须 */ ,
                Region: this.Region /* 存储桶所在地域,必须字段 */ ,
                Key: `quality/${details.model}/${details.code}/${urls[urls.length-imageFiles.length+index]}` /* 必须 */ ,
                Body: item,
                Sign: true
            })
        })
        // ? 该部分SecretId暂时固定
    postAction(this.getCosUrl, formData).then((res) => {
        if (res.success) {
            let result = JSON.parse(res.message)
            let tmpSecretId = result.credentials.tmpSecretId,
                tmpSecretKey = result.credentials.tmpSecretKey,
                sessionToken = result.credentials.sessionToken
            var cos = new COS({
                getAuthorization: function(options, callback) { 
                    // var authorization = COS.getAuthorization({
                    //     // SecretId: 'AKIDMjxwd4S9pFQKzNfVEjyxg9LQE8nAnCpC',
                    //     // SecretKey: 'mHqAHNFrDQ2Vki028yf5FD0XZeUAbnjT',
                    //     SecretId: tmpSecretId,
                    //     SecretKey: tmpSecretKey,
                    //     Token: sessionToken,
                    //            Method: options.Method,
                    //            Key: options.Key,
                    //            Query: options.Query,
                    //            Headers: options.Headers,
                    //            Expires: 60,
                    // });
                    // callback(authorization);
                    callback({
                        TmpSecretId: tmpSecretId,
                        TmpSecretKey: tmpSecretKey,
                        XCosSecurityToken: sessionToken,
                        // 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
                        StartTime: result.startTime, // 时间戳,单位秒,如:1580000000
                        ExpiredTime: result.expiredTime, // 时间戳,单位秒,如:1580000900
                    });
                }
            });
            cos.uploadFiles({
                files,
                SliceSize: 1024 * 1024,
                onProgress: info => {
                    var percent = parseInt(info.percent * 10000) / 100;
                    var speed = parseInt(info.speed / 1024 / 1024 * 100) / 100;
                    console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;');
                },
                onFileFinish: (err, data, options) => {
                    console.log(options.Key + '上传' + (err ? '失败' : '完成'));
                },
            }, (err, data) => {
                let status = err ? 500 : 200
                if (status == 200) {
                    const formData2 = new FormData()
                    formData2.append('code', details.code)
                    formData2.append('name', details.name)
                    formData2.append('picName', urls)
                    postAction(this.upload, formData2).then(res => {
                        if (res.success) {
                            this.$message.success(res.message)
                            this.$emit("display");
                        } else {
                            this.$message.error(res.message)
                        }
                        this.visible = false
                    })
                } else {
                    this.$message.warning('操作失败')
                }
            });
        } else {
            this.$message.warning(res.message)
        }
    }, (err) => {
        let res = Object.assign({}, {
            message: "执行失败",
            success: false
        })
        _that.uploadResult = res
        this.$message.warning(err)
    })
}

将url地址的文件下载
链接: https://blog.csdn.net/qq_43305958/article/details/108366645.

总结


good afternoon

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值