前端使用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