实现大文件上传全流程详解(补偿版本)

之前分享了大文件上传的前端实现后,但是还有很多细节没有说明,隔了这么久又来考古一下Orz.

在日常开发中,大文件上传是个绕不开的坎——动辄几百 MB 甚至 GB 级的文件,直接上传不仅容易超时,还会让用户体验大打折扣。最近我用 Vue+Express 实现了一套完整的大文件上传方案,支持分片上传、断点续传、秒传和手动中断,今天就带大家从头到尾盘清楚其中的技术细节。

一、先看效果:我们要实现什么?

先上核心功能清单,确保大家明确目标,知道我们要解决哪些实际问题:

  • 大文件分片上传:将文件切成固定大小的小片段分批上传,避免单次请求超时
  • 秒传:服务器已存在完整文件时,直接返回成功,无需重复上传
  • 断点续传:刷新页面或上传中断后,仅上传未完成的分片,无需从头开始
  • 并发控制:限制同时上传的分片数量,避免请求过多导致浏览器 / 服务器崩溃
  • 手动中断:支持用户随时停止上传,且中断后已传分片不丢失

最终交互很简洁:一个文件选择框 + 上传中的中断按钮,但背后是一整套覆盖「上传前 - 上传中 - 上传后」的完整逻辑。

二、全流程拆解:从选文件到合并

我们先从宏观视角梳理整个流程,再拆分成前端和后端的具体实现。整个过程可总结为「5 步走」,每一步都有明确的目标和技术要点:

用户选择文件 → 前端分片+算哈希 → 校验文件状态(秒传/断点续传) → 并发上传分片 → 后端合并分片

第一步:用户选择文件(前端触发)

这是流程的起点,通过原生 <input type="file"> 获取用户选择的文件,在 onchange 事件中触发后续逻辑。

<template>
  <div class="upload-container">
    <h2>大文件上传演示</h2>
    <input @change="handleUpload" type="file" class="file-input" />
    <!-- 上传中才显示中断按钮 -->
    <button @click="abortUpload" v-if="isUploading" class="abort-btn">
      中断上传
    </button>
  </div>
</template>

<script setup>
import { ref } from "vue";

// 上传状态管理
const isUploading = ref(false); // 是否正在上传
const abortControllers = ref([]); // 存储所有请求的中断控制器

const handleUpload = async (e) => {
  const file = e.target.files[0]; // 获取用户选择的单个文件
  if (!file) return; // 未选文件则退出

  // 后续核心逻辑:分片、算哈希、校验...
  // (下文逐步展开)
};
</script>

<style scoped>
.upload-container { margin: 20px; }
.file-input { margin-right: 10px; }
.abort-btn { padding: 4px 8px; background: #ff4444; color: white; border: none; border-radius: 4px; }
</style>

第二步:前端分片 + 计算文件哈希

大文件直接上传会触发超时,因此必须先「拆小」;而哈希值是实现「秒传」和「断点续传」的核心 —— 它是文件的唯一标识,用于告诉服务器 “这是哪个文件”。

2.1 文件分片:把大文件切成小片段

用浏览器原生 API File.slice() 按固定大小(这里设为 1MB)切割文件,得到多个 Blob 对象(即「分片」)。

运行

// 分片大小:1MB(可根据需求调整,如5MB/10MB)
const CHUNK_SIZE = 1024 * 1024; 

/**
 * 生成文件分片数组
 * @param {File} file - 用户选择的原始文件
 * @returns {Blob[]} 分片数组
 */
const createChunks = (file) => {
  let cur = 0; // 当前切割位置
  let chunks = [];
  while (cur < file.size) {
    // 从当前位置切割到「当前位置+分片大小」,最后一片可能不足1MB
    const blob = file.slice(cur, cur + CHUNK_SIZE);
    chunks.push(blob);
    cur += CHUNK_SIZE;
  }
  return chunks;
};

// 示例:3.5MB 的文件会生成 4 个分片(1MB+1MB+1MB+0.5MB)

2.2 计算文件哈希:生成唯一标识

用 spark-md5 库计算文件哈希,但有个关键优化:不读取整个文件,而是抽样读取部分片段(首尾分片全量 + 中间分片抽样),既能保证哈希唯一性,又能大幅提升大文件的计算速度。

先安装依赖:

npm install spark-md5 --save

再实现哈希计算逻辑:

import sparkMD5 from "spark-md5";

/**
 * 计算文件哈希值(抽样优化)
 * @param {Blob[]} chunks - 分片数组
 * @returns {Promise<string>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值