
1 安装依库 npm install spark-md5 --save
2 引入 import SparkMD5 from "spark-md5";
3pnpm install express multer cors
4 打开终端 cmd node启动 node bigfileserver.js
前端代码BigFileshangchuan.vue
<template><div class="upload-container"><input type="file" @change="handleFileChange" /><button @click="upload" :disabled="!file">上传</button><div v-if="progress > 0" class="progress">上传进度:{{ progress.toFixed(2) }}%</div></div>
</template><script setup>
import { ref } from "vue";
import SparkMD5 from "spark-md5";
// 1 安装依库 npm install spark-md5 --save
// 2 引入 import SparkMD5 from "spark-md5";
const file = ref(null);
const progress = ref(0);
const chunkSize = 3 * 1024 * 1024; // 每片3MBfunction handleFileChange(e) {file.value = e.target.files[0];console.log("🚀 ~ handleFileChange ~ file.value :", file.value )
}// 上传主流程
async function upload() {if (!file.value) return;console.log("🚀 ~ upload ~ file.value:", file.value)const fileSize = file.value.size;console.log("🚀 ~ upload ~ fileSize:", fileSize)const chunkCount = Math.ceil(fileSize / chunkSize);// 存储切片const chunkAll = [];const spark = new SparkMD5.ArrayBuffer();// 逐片生成for (let i = 0; i < chunkCount; i++) {const chunkItem = await createChunk(file.value, i, chunkSize);chunkAll.push(chunkItem);progress.value = ((i + 1) / chunkCount) * 50; // 生成分片阶段进度}// 计算整文件MD5const fullMd5 = await calculateFileMD5(file.value);// 构造 FormDataconst formData = new FormData();chunkAll.forEach((item) => {formData.append("chunk", item.blob, `chunk${item.index}`);});formData.append("MD5", fullMd5);// 发送请求
// const res = await fetch("http://localhost:3000/upload", {
// method: "POST",
// body: formData,
// });const res = await fetch("http://localhost:3000/upload", {method: "POST",body: formData,
});const result = await res.json();console.log(result);progress.value = 100;alert("上传完成!");
}// 生成单个分片
function createChunk(file, index, chunkSize) {return new Promise((resolve) => {const start = index * chunkSize;const end = Math.min(file.size, start + chunkSize);const blob = file.slice(start, end);const spark = new SparkMD5.ArrayBuffer();const reader = new FileReader();reader.readAsArrayBuffer(blob);reader.onload = (e) => {spark.append(e.target.result);resolve({index,start,end,MD5: spark.end(),blob,});};});
}// 计算整文件MD5
function calculateFileMD5(file) {return new Promise((resolve) => {const reader = new FileReader();const spark = new SparkMD5.ArrayBuffer();reader.readAsArrayBuffer(file);reader.onload = (e) => {spark.append(e.target.result);resolve(spark.end());};});
}
</script><style scoped>
.upload-container {padding: 20px;
}
button {margin-left: 10px;padding: 5px 10px;
}
.progress {margin-top: 10px;color: #2c7a7b;
}
</style>
模拟后端代码bigfileserver.js
/*
模拟后端大文件分片上传服务
1pnpm init -y
2pnpm install express multer cors
3 打开终端 cmd node启动 node bigfileserver.jsexpress:Web 框架multer:处理 multipart/form-data(文件上传)cors:允许前端跨域请求
*/
import express from "express";
import multer from "multer";
import cors from "cors";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";// __dirname 在 ES Module 下需要自己定义
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);const app = express();
const PORT = 3000;app.use(cors());// 设置上传目录
const upload = multer({ dest: "uploads/" });// 用于记录上传开始时间
let startTime = null;app.post("/upload", upload.array("chunk"), (req, res) => {if (!startTime) startTime = Date.now();let totalSize = 0;console.log("接收到分片数量:", req.files.length);// 保存分片,同时累加总文件大小req.files.forEach((file) => {const targetPath = path.join(__dirname, "uploads", file.originalname);fs.renameSync(file.path, targetPath); // 保存分片totalSize += file.size;console.log(`分片: ${file.originalname}, 大小: ${(file.size / 1024 / 1024).toFixed(2)} MB`);});console.log(`本次请求上传总大小: ${(totalSize / 1024 / 1024).toFixed(2)} MB`);// 判断是否最后一片,这里假设前端最后一个请求 MD5 最大值已传const md5 = req.body.MD5;if (md5) {const endTime = Date.now();console.log(`上传完成,总耗时: ${(endTime - startTime) / 1000}s`);console.log(`整文件大小: ${(totalSize / 1024 / 1024).toFixed(2)} MB`);startTime = null;}res.json({ code: 0, msg: "分片上传成功" });
});app.listen(PORT, () => {console.log(`Server running on http://localhost:${PORT}`);
});