使用场景:固定音频视频上传时由于文件过于大一些后台产品往往将其请求设置为5000毫秒超过该事件限制则自动结束请求并返回请求超时 request timeout 这样的返回信息或者直接是代码值为500,所以这时候最佳解决方案就是亚马逊云的分片上传模块
1.请求后台接口获取身份信息等数据用于访问
2.createMultipartUpload创建上传请求
身份信息
/* data为第一步时请求后台接口并返回的值
身份信息必传 */
/// 相关参数信息
accessKeyId: '通过身份认证信息时接口返回的相关id信息',
secretAccessKey: '通过身份认证信息时接口返回的唯一key',
sessionToken: '通过身份认证信息时接口返回的身份证明',
要用秘钥的形式登录上传
endpoint: '请求的地址 默认是亚马逊的地址(传自己服务器的地址)',
createMultipartUpload具体传递的参数
必须值
Bucket: 桶,
Key: Key,
ACL: ‘public-read’,
注:ACL可传可不传
3.分片
(1)这一整个流程是按照我们将文件开始上传的时候就开始的 处理文件的步骤是第三步,所以我们只有确保前两个步骤没有问题才可以进行第三步
(2)当我们进行到这一步的时候就可以进行我们的文件处理
/// file 为我们拿到的我们要上传的文件
var size = 5000 // 我们要切片的每个文件的大小
// 我们要获取到文件的大小 然后用文件的大小除去我们即将要切片的子文件的大小
注:该步骤需要注意文件大小单位的统一
let fileList = [] // 这里是我们拿到的分割好的文件的数组
for(let i = 0; i < file.size / size; i++){
fileLIst.push(file.slice(i,i+size))
}
// 到这里我们就将我们的文件处理好了 下面就要开始上传操作
4.uploadPart上传分片的每一部分
PartNumber: '唯一id使用变量', // 1 ~ 10,000
UploadId: 这是createMultipartUpload里返回的ID值用于后续所有操作不可或缺, // s3.createMultipartUpload
Body: (二进制文件 string类型),
Bucket: 桶名,
Key: Key值,
5.abortMultipartUpload若失败则删除所有
Bucket: 桶名,
Key: Key值,
UploadId: 这是createMultipartUpload里返回的ID值用于删除失败后的整条数据,
6.listParts获取上传列表
Bucket: 桶名,
Key: Key值,
UploadId: 这是createMultipartUpload里返回的ID值用于获取当前ID的上传列表
7.completeMultipartUpload合并上传分片
Bucket: 桶名,
Key: Key值,
MultipartUpload: {
Parts: [
{
ETag:'listParts下的data返回值用于合并',
PartNumber:'上传分片时分片的ID值',
}
],
},
这是createMultipartUpload里返回的ID值用于合并当前ID下的所有分片
createMultipartUpload请求成功后会有data下的Location是成功存储后的地址
具体代码 注释见下文
这个是基于vue3的写法 和JS也差不多 上传用的是elementUI upload组件
// **上传视频**
let object = [];
/* handlevideoUpload :绑定上传视频方法 需要传file参数
后面会将file转二进制通过uploadPart方法上传至亚马逊方法里进行分片储存 */
const handlevideoUpload = async (file) => {
window.console.log(file);
/* 拿到file将name传递至后端 请求接口获取桶、session、key等值 */
let formData = new FormData();
formData.append('filename', file.file.name);
const { data } = await awsary(formData);
state.data = data;
/* 赋值至开头的object里后面会用的到 作用是方便其他方法调用 */
let obj = data;
/* 将后台返回的相关身份信息等数剧赋值给 credentials 参数名称不可变为亚马逊固定 参数是后台返回 */
var credentials = {
accessKeyId: data.accessKey,
secretAccessKey: data.secretKey,
sessionToken: data.sessionToken,
};
// 秘钥形式的登录上传
// endpoint:为请求地址必须得改 在请求时注意异步 若异步可在服务器设置相关权限 具体请求有 post put get等 若有写上传失败等方法需要delete权限
AWS.config.update(credentials);
var bucket = new AWS.S3({
s3BucketEndpoint: true,
region: data.region,
endpoint: data.endpoint,
});
if (file) {
/* params 为创建上传请求的参数ACL可传可不传 参数名称不可更改 参数值具体以后台接口返回为准 */
var params = {
Bucket: data.bucket,
Key: data.oss_path,
ACL: 'public-read',
};
// 切片处理 在uploadPart里需要转成二进制方法进行上传然后list方法才会返回上传列表
const size = file.file.size; // 文件总大小
const partSize = 1024 * 1024 * 50;// 要分的文件大小 这里是50MB
let partNumber = 0;//分片ID可自定义 是为了在合并时找到对应的文件和顺序
let forNumber = Math.ceil(size / partSize); // 向上取整、确保不会有分片文件遗漏
state.PartForNumber = forNumber; // state是VUE3 TS的写法JS可用this 写在return下
// createMultipartUpload // bucket是上文中定义的对象 内包含了请求地址等信息 这一步是创建上传请求 获取上传唯一ID 后面都会用到
bucket.createMultipartUpload(params, function (err, data) {
/* data.UploadId:是正确上传后返回的data值 若为返回则打印err 获取具体的上传失败的原因后面的可以用if(!err){}else{}包起来防止报错后代码继续执行 */
state.upload_id = data.UploadId;
/* 此处循环为处理分片上传的方法 */
for (let i = 0; i < forNumber; i++) {
partNumber++;//上传的ID
window.console.log(i, forNumber);
var blob = new Blob([file.file], { type: file.file.type });
// 将文件转为二进制流准备切片以及上传
window.console.log(blob);
const blob2 = blob.slice(i * partSize, i * partSize + partSize);
// 上传处理 i * partSize相当于开始的参数,i * partSize + partSize为结束的参数 建议像我这样写否则切片出来的文件size会丢失 导致后面下载的文件无法播放等问题
window.console.log(blob2);
/* 上传文件参数参数名不可更改为亚马逊固定必传参数 */
const uploadPart_params = {
PartNumber: partNumber, // 1 ~ 10,000
UploadId: data.UploadId, // s3.createMultipartUpload
Body: blob2,// 次数必须是二进制文件流 不要用formData 需要自己处理好
Bucket: obj.bucket,//桶名 一直都需要传
Key: obj.oss_path,
};
window.console.log(uploadPart_params);
/* 开始上传 我在写的时候无法用.then()所以单独拉出来一个方法去做判断是否执行、大文件循环结束后但是上传的请求还是在处理中、所以我单独拉出来一个方法、用来走后续的方法 */
bucket.uploadPart(uploadPart_params, function (err, data) {
/* 我是判断了有没上传成功然后去做后续的处理、若没有上传成功调用abortMultipartUpload()、去删除这个ID下的文件、因为是分片所以每一个都需要判断、一个失败则全部失败*/
if (err) {
ElMessage.warning('上传失败请重新上传');
var params = {
Bucket: obj.bucket,
Key: obj.oss_path,
UploadId: state.upload_id,
};
bucket.abortMultipartUpload(params, function (err, data) {});
}
object.push('err');
window.console.log('partNumber == forNumber', partNumber == forNumber);
window.console.log('err', !err);
/* 我自己定义的方法、用来调用后面的步骤 */
getListData();
});
};
}
uploadPart();
}
});
} else {
window.alert('');
}
};
const getListData = () => {
// 这里因为上边我不是全局定义所以这里又重新定义了一次
var credentials = {
accessKeyId: state.data.accessKey,
secretAccessKey: state.data.secretKey,
sessionToken: state.data.sessionToken,
};
//秘钥形式的登录上传
AWS.config.update(credentials);
var bucket = new AWS.S3({
s3BucketEndpoint: true,
region: state.data.region,
endpoint: state.data.endpoint,
});*/
// 判断是我成功请求的长度是否等于我分片的长度等于则执行 不等于就不要让执行了 因为执行了也是失败 获取到的list里的上传列表是不全的所以还是不要执行了后续拿到的文件也是有问题的
if (object.length == state.PartForNumber) {
window.console.log('err', 'err');
var paramslist = {
Bucket: state.data.bucket,
Key: state.data.oss_path,
UploadId: state.upload_id,
};
window.console.log(paramslist);
/* 获取上传列表 */
bucket.listParts(paramslist, function (err, data) {
if (err) window.console.log(err, err.stack);
else {
window.console.log(data);
let eTagParts = [];
data.Parts.map((item) => {
// 因为最后一步是将分好的片合起来 所以我们这里需要拿到每一个的ETag和PartNumber(上传时每一个分片的ID)
eTagParts.push({
ETag: item.ETag,
PartNumber: item.PartNumber,
});
});
// window.console.log(uploadPart_params);
const params_com = {
Bucket: state.data.bucket,
Key: state.data.oss_path,
MultipartUpload: {
Parts: eTagParts,
},
UploadId: state.upload_id,
};
window.console.log(params_com);
// 最后一步合分片 注意上面的参数部分MultipartUpload的格式否则会报错
bucket.completeMultipartUpload(params_com, function (err, data) {
// 到了这一步那就是成功不远了 如果失败了则返回err信息 成功则返回data信息
window.console.log(params_com);
window.console.log(data);
window.console.log(err);
});
}
});
}
};
当你最后一步打印出来的data是这样的 那么恭喜你 你的分片
做好了 [烟花][烟花][烟花][烟花][烟花][烟花]