之前分享了大文件上传的前端实现后,但是还有很多细节没有说明,隔了这么久又来考古一下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>

最低0.47元/天 解锁文章
2660

被折叠的 条评论
为什么被折叠?



