赞
踩
上传大文件(比如3GB)时,一般不能调用一次接口上传完,接口会超时或报错,这时候需要前端把大文件分片处理一下,再分别调用接口上传分片文件,全部分片上传完后,由后端将所有分片合并和返回最终的文件地址。
async handleAvatarUploadDemo({ file }) { ..... //MD5加密 const md5 = await this.handleFile(file); const chunkSize = 10 * 1024 * 1024; // 10MB 每个分片的大小 let start = 0; let end = Math.min(chunkSize, file.size); let index = 0; const uploadChunk = (file, start, end, index) => { const chunk = file.slice(start, end); // 切割文件为分片 let formData = new FormData(); formData.append('file', chunk); formData.append('index', index); formData.append('totalChunks', Math.ceil(file.size / chunkSize)); formData.append('md5', md5); axios .post( '/api/spang-system/oss/endpoint/put-file-flake', formData, // 直接传递formData对象 { headers: { 'Content-Type': 'multipart/form-data' }, timeout: 600000, } ) .then(res => { // 处理分片上传成功的响应 index++; start = end; end = Math.min(start + chunkSize, file.size); if (file.size - start < 5 * 1024 * 1024 && start !== 0) { // 最后一个切片大小小于5MB且不是第一个切片 start = end; end = file.size; // 设置结束位置为文件末尾start = Math.max(0, end - chunkSize); // 重新计算起始位置 } if (start < file.size) { uploadChunk(file, start, end, index); // 递归上传下一个分片,并传递file参数 } else { // 所有分片上传完成 // 合并分片等操作 const param = { md5: md5, originalFilename: fileName }; axios .get(`/api/spang-system/oss/endpoint/file-merge`, { params: param, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, timeout: 600000, //十分钟超时 }) .then(res => { ...... loading.close(); }) .catch(e => { loading.close(); // 处理分片上传失败 console.error('文件上传失败:', e); }); } }) .catch(e => { loading.close(); // 处理分片上传失败 console.error('文件上传失败:', e); }); }; uploadChunk(file, start, end, index); },
注意:判断是不是最后一个分片前的这段代码,不是必须的,后端要求最后一个分片小于5MB的话,不要调分片接口单独传一次,要求和最后一个分片(原来倒数第二个分片)一起传给接口,所以加了这个判断,具体业务具体分析
if (file.size - start < 5 * 1024 * 1024 && start !== 0) {
// 最后一个切片大小小于5MB且不是第一个切片
start = end;
end = file.size; // 设置结束位置为文件末尾start = Math.max(0, end - chunkSize); // 重新计算起始位置
}
用于表示不可变的、原始数据的类文件对象。它通常用于处理二进制数据,比如文件内容或者从其他数据源获取的数据。
// 创建一个包含文本的Blob对象
const blob = new Blob(["Hello, world!"], { type: 'text/plain' });
// 读取Blob对象的内容
const reader = new FileReader();
reader.onload = function(event) {
console.log(event.target.result); // "Hello, world!"
};
reader.readAsText(blob);
new File() 是一个构造函数,用于创建一个新的 File 对象,代表有关用户文件的信息。这个对象可以用来读取文件内容或上传文件到服务器。
注意:可以将Blob格式转化成File文件
// 假设有一个Blob对象,代表一些数据
const blob = new Blob(["Hello, world!"], { type: 'text/plain' });
// 创建一个新的File对象
const file = new File([blob], "helloWorld.txt", {
type: "text/plain",
lastModified: new Date()
});
// 现在可以将这个File对象用于读取或上传等操作
console.log(file.name); // "helloWorld.txt"
new FormData() 是一个构造函数,用于创建一个新的 FormData 对象,它是一种表示表单数据键值对的方式,可以用于异步上传表单数据。
// 创建一个新的FormData对象
const formData = new FormData();
// 可以添加键值对,这里的file是一个File对象
formData.append('file', file, file.name);
// 现在可以将FormData对象用于XMLHttpRequest或fetch来异步上传表单数据
fetch('/upload', {
method: 'POST',
body: formData
});
File 对象代表单个文件的内容和属性,通常用于读取或上传文件。
FormData 对象用于构建一组键值对,表示表单字段和其值,可以包含 File 对象。它通常用于通过HTTP请求发送表单数据,特别是当表单包含文件上传时。
简而言之,File 对象用于表示文件,而 FormData 对象用于打包表单数据,包括文件,以便发送到服务器。
//文件分片和上传 async handleAvatarUploadDemo({ file }, key = '', idx = null) { const isMp3 = file.type === 'audio/mp3' || file.type === 'audio/mpeg'; const isMp4 = file.type === 'video/mp4'; const isPdf = file.type === 'application/pdf'; const fileType = isMp3 ? 'mp3' : isMp4 ? 'mp4' : isPdf ? 'pdf' : ''; const fileName = file.name; const loading = this.$loading({ lock: true, text: '文件上传中, 请稍候...', spinner: 'el-icon-loading', target: '#centerLoading', }); //MD5加密 const md5 = await this.handleFile(file); const chunkSize = 10 * 1024 * 1024; // 10MB 每个分片的大小 let start = 0; let end = Math.min(chunkSize, file.size); let index = 0; const uploadChunk = (file, start, end, index) => { const chunk = file.slice(start, end); // 切割文件为分片 let formData = new FormData(); formData.append('file', chunk); formData.append('index', index); formData.append('totalChunks', Math.ceil(file.size / chunkSize)); formData.append('md5', md5); axios .post( '/api/spang-system/oss/endpoint/put-file-flake', formData, // 直接传递formData对象 { headers: { 'Content-Type': 'multipart/form-data' }, timeout: 600000, } ) .then(res => { // 处理分片上传成功的响应 index++; start = end; end = Math.min(start + chunkSize, file.size); if (file.size - start < 5 * 1024 * 1024 && start !== 0) { // 最后一个切片大小小于5MB且不是第一个切片 start = end; end = file.size; // 设置结束位置为文件末尾start = Math.max(0, end - chunkSize); // 重新计算起始位置 // start = Math.max(0, end - chunkSize); // 重新计算起始位置 } if (start < file.size) { uploadChunk(file, start, end, index); // 递归上传下一个分片,并传递file参数 } else { // 所有分片上传完成 // 合并分片等操作 const param = { md5: md5, originalFilename: fileName }; axios .get(`/api/spang-system/oss/endpoint/file-merge`, { params: param, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, timeout: 600000, //十分钟超时 }) .then(res => { if (key == 'cover1') { this.ruleForm.coursewarePath = res.data.data.link; this.ruleForm.coursewareType = fileType; this.ruleForm.coursewareName = res.data.data.originalName; this.coursewarePath1 = [{ name: res.data.data.originalName, url: res.data.data.link }]; } else if (key == 'cover2') { this.ruleForm.multipleChapters[idx].coursewarePath = res.data.data.link; this.ruleForm.multipleChapters[idx].coursewareType = fileType; this.ruleForm.multipleChapters[idx].coursewareName = res.data.data.originalName; this.ruleForm.multipleChapters[idx].fileList = [ { name: res.data.data.originalName, url: res.data.data.link }, ]; } loading.close(); }) .catch(e => { loading.close(); // 处理分片上传失败 console.error('文件上传失败:', e); }); } }) .catch(e => { loading.close(); // 处理分片上传失败 console.error('文件上传失败:', e); }); }; uploadChunk(file, start, end, index); }, // md5文件加密 handleFile(file) { return new Promise((resolve, reject) => { const chunkSize = 2097152; // 2MB const fileReader = new FileReader(); const spark = new SparkMD5.ArrayBuffer(); let cursor = 0; fileReader.onerror = function () { reject('Error reading file'); }; fileReader.onload = function (e) { spark.append(e.target.result); // Append array buffer cursor += e.target.result.byteLength; if (cursor < file.size) { readNext(); } else { resolve(spark.end()); } }; function readNext() { const fileSlice = file.slice(cursor, cursor + chunkSize); fileReader.readAsArrayBuffer(fileSlice); } readNext(); }); },
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。