前端如何实现大文件分片上传

无论是上传视频、图片还是其他大文件,分片上传都是提升上传效率和稳定性的关键!那么前端如何实现 大文件分片上传呢?


1. 为什么需要分片上传?

  • 解决大文件上传问题:避免一次性上传大文件导致的内存溢出或超时问题。
  • 提升上传效率:分片上传可以并行上传多个分片,充分利用带宽。
  • 增强稳定性:如果某个分片上传失败,只需重传该分片,而不是整个文件。

2. 分片上传的实现步骤

(1)前端分片

  • 将文件切割成固定大小的分片(如 1MB)。
  • 使用 File.prototype.slice 方法切割文件。

(2)上传分片

  • 使用 FormData 将分片数据上传到服务器。
  • 每个分片上传时携带分片序号、文件唯一标识等信息。

(3)服务器合并分片

  • 服务器接收到所有分片后,按顺序合并分片,还原完整文件。

(4)断点续传

  • 记录已上传的分片,上传失败时从中断处继续上传。

3. 前端代码实现

以下是一个简单的分片上传实现:

(1)HTML 部分

bash 复制代码
<input type="file" id="file-input" />
<button id="upload-btn">上传</button>

(2)JavaScript 部分

javascript 复制代码
const CHUNK_SIZE = 1 * 1024 * 1024; // 每个分片大小为 1MB

document.getElementById('upload-btn').addEventListener('click', async () => {
  const file = document.getElementById('file-input').files[0];
  if (!file) {
    alert('请选择文件');
    return;
  }

  const fileSize = file.size;
  const chunks = Math.ceil(fileSize / CHUNK_SIZE); // 计算分片数量
  const fileHash = await calculateFileHash(file); // 计算文件唯一标识
  let uploadedChunks = 0; // 已上传的分片数量

  for (let i = 0; i < chunks; i++) {
    const start = i * CHUNK_SIZE;
    const end = Math.min(fileSize, start + CHUNK_SIZE);
    const chunk = file.slice(start, end); // 切割分片

    const formData = new FormData();
    formData.append('file', chunk);
    formData.append('chunkIndex', i);
    formData.append('totalChunks', chunks);
    formData.append('fileHash', fileHash);

    try {
      await uploadChunk(formData); // 上传分片
      uploadedChunks++;
      console.log(`分片 ${i + 1}/${chunks} 上传成功`);
    } catch (error) {
      console.error(`分片 ${i + 1}/${chunks} 上传失败`, error);
      return;
    }
  }

  console.log('所有分片上传完成,通知服务器合并文件');
  await mergeChunks(fileHash, file.name); // 通知服务器合并分片
});

// 计算文件唯一标识(MD5)
function calculateFileHash(file) {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.readAsArrayBuffer(file);
    reader.onload = () => {
      const buffer = reader.result;
      const spark = new SparkMD5.ArrayBuffer();
      spark.append(buffer);
      resolve(spark.end());
    };
  });
}

// 上传分片
function uploadChunk(formData) {
  return fetch('/upload-chunk', {
    method: 'POST',
    body: formData,
  }).then((response) => {
    if (!response.ok) throw new Error('上传失败');
  });
}

// 通知服务器合并分片
function mergeChunks(fileHash, fileName) {
  return fetch('/merge-chunks', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ fileHash, fileName }),
  }).then((response) => {
    if (!response.ok) throw new Error('合并失败');
  });
}

5. 断点续传的实现

  • 记录已上传的分片 :前端可以在本地存储(如 localStorage)中记录已上传的分片。
  • 跳过已上传的分片:在上传前检查分片是否已上传,避免重复上传。

6. 优化建议

  1. 并行上传 :使用 Promise.all 并行上传多个分片,提升上传速度。
  2. 进度显示:实时显示上传进度,提升用户体验。
  3. 错误重试:为每个分片设置重试机制,增强上传稳定性。
  4. 压缩分片:在上传前对分片进行压缩,减少上传数据量。

总结

通过分片上传,可以有效解决大文件上传的问题,提升上传效率和稳定性。前端使用 File.slice 切割文件,服务器端按顺序合并分片,结合断点续传和并行上传,可以实现高效可靠的大文件上传功能!

相关推荐
子兮曰2 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰2 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万2 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝2 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
A黄俊辉A2 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
三十而立洋2 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁2 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄2 天前
JavaScript 隐式全局变量解析
javascript
honkun62 天前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
kybs19912 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net