大文件传输与断点续传实现(极简Demo:React+Node.js)

简述

使用React前端和Node.js后端实现大文件传输和断点续传的功能。通过分片上传技术,可以有效地解决网络不稳定带来的传输中断问题。

文章内容

前端实现(React)

首先,您需要在前端项目中安装axios库以处理HTTP请求。可以使用以下命令:

npm i axios

以下是实现大文件上传的React组件代码:

import axios from 'axios';
import { useRef, useState } from 'react'; // 定义文件分片大小(例如 5MB)
const CHUNK_SIZE = 5 * 1024 * 1024; /** 解析当前页面功能 */
export default function FileUploader() {
const [file, setFile] = useState(null); // 用于存储用户选择的文件
const [uploadProgress, setUploadProgress] = useState(0); // 上传进度
const uploading = useRef(false); // 用于防止重复触发上传逻辑 // 当用户选择文件时触发
const handleFileChange = (e) => {
setFile(e.target.files[0]); // 将选择的文件存入状态
setUploadProgress(0); // 重置上传进度
}; // 计算文件的唯一标识 (哈希)
const calculateFileHash = async (file) => {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = (e) => {
const sparkMD5 = require('spark-md5');
const hash = sparkMD5.ArrayBuffer.hash(e.target.result);
resolve(hash);
};
reader.readAsArrayBuffer(file);
});
}; // 开始文件上传
const handleUpload = async () => {
if (!file || uploading.current) return; // 如果未选择文件或正在上传,则直接返回 uploading.current = true; // 标记为正在上传
const fileHash = await calculateFileHash(file); // 获取文件的唯一标识(哈希值)
console.log('fileHash', fileHash);
const totalChunks = Math.ceil(file.size / CHUNK_SIZE); // 计算文件分片总数
// 检查哪些分片已经上传
const { data: uploadedChunks } = await axios.post(
'http://localhost:5000/check',
{
fileName: file.name,
fileHash,
},
); // 上传未完成的分片
for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
if (uploadedChunks?.includes(chunkIndex)) {
console.log('跳过chunkIndx', chunkIndex);
setUploadProgress(((chunkIndex + 1) / totalChunks) * 100); // 更新进度
continue; // 跳过已经上传的分片
}
console.log('上传chunkIndx', chunkIndex);
// 创建当前分片
const start = chunkIndex * CHUNK_SIZE; // 分片起始字节
const end = Math.min(file.size, start + CHUNK_SIZE); // 分片结束字节
const chunk = file.slice(start, end); // 获取分片 // 上传分片
const formData = new FormData();
formData.append('chunk', chunk); // 当前分片
formData.append('fileName', file.name); // 文件名
formData.append('fileHash', fileHash); // 文件唯一标识
formData.append('chunkIndex', chunkIndex); // 分片索引 await axios.post(
`http://localhost:5000/upload?fileHash=${fileHash}&chunkIndex=${chunkIndex}&fileName=${file.name}`,
formData,
{
onUploadProgress: (progressEvent) => {
const progress =
((chunkIndex + progressEvent.loaded / progressEvent.total) /
totalChunks) *
100;
setUploadProgress(progress); // 实时更新上传进度
},
},
);
} // 通知服务端合并分片
await axios.post('http://localhost:5000/merge', {
fileName: file.name,
fileHash,
totalChunks,
}); alert('上传成功!');
uploading.current = false; // 标记上传完成
}; return (
<div style={{ padding: '20px' }}>
<p>大文件上传(支持断点续传)</p>
<input type="file" onChange={handleFileChange} />
<button onClick={handleUpload}>提交上传文件</button>
<div style={{ marginTop: '20px' }}>
<progress value={uploadProgress} max="100" />
<div>上传进度:{uploadProgress.toFixed(2)}%</div>
</div>
</div>
);
}

后端实现(Node.js)

在后端,您需要安装以下依赖:multerfs-extraexpresscorsbody-parser。可以使用以下命令:

npm i multer fs-extra express cors body-parser

注意: 这些包应用于生产环境和开发环境。

以下是Node.js服务器的实现代码:

// 文件:server.js
const express = require("express");
const multer = require("multer");
const fs = require("fs");
const bodyParser = require("body-parser");
const path = require("path");
const cors = require("cors");
const app = express();
const uploadDir = path.join(__dirname, "uploads"); // 上传目录 // 确保上传目录存在
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir);
} app.use(cors()); // 允许跨域请求
app.use(bodyParser.json());
app.use(express.json()); // 解析 JSON 请求体 // 检查已上传的分片
app.post("/check", (req, res) => {
const { fileHash } = req.body;
console.log("fileHash check",fileHash) const fileChunkDir = path.join(uploadDir, fileHash); // 分片存储目录
if (!fs.existsSync(fileChunkDir)) {
return res.json([]); // 如果目录不存在,返回空数组
} // 返回已上传的分片索引
const uploadedChunks = fs.readdirSync(fileChunkDir).map((chunk) => {
return parseInt(chunk.split("-")[1]); // 提取分片索引
});
res.json(uploadedChunks);
}); // 设置 multer 中间件,用于处理文件上传
const storage = multer.diskStorage({
destination: (req, file, cb) => {
const fileHash = req.query.fileHash; // 从查询参数获取 fileHash
const chunkDir = path.join(uploadDir, fileHash);
// 确保切片目录存在
if (!fs.existsSync(chunkDir)) {
fs.mkdirSync(chunkDir, { recursive: true });
}
cb(null, chunkDir);
},
filename: (req, file, cb) => {
const { chunkIndex } = req.query;
cb(null, `chunk-${chunkIndex}`);
},
}); const upload = multer({ storage:storage }); // 上传文件分片
app.post("/upload", upload.single("chunk"), (req, res) => {
const { fileHash } = req.body;
res.status(200).send("分片上传成功");
}); // 合并分片
app.post("/merge", (req, res) => {
const { fileName, fileHash, totalChunks } = req.body;
console.log("fileName",req.body)
const fileChunkDir = path.join(uploadDir, fileHash);
const filePath = path.join(uploadDir, fileName); // 创建可写流用于最终合并文件
const writeStream = fs.createWriteStream(filePath); for (let i = 0; i < totalChunks; i++) {
const chunkPath = path.join(fileChunkDir, `chunk-${i}`);
const data = fs.readFileSync(chunkPath); // 读取分片
writeStream.write(data); // 写入最终文件
// fs.unlinkSync(chunkPath); // 删除分片文件--留下来,可以看上传记录
} writeStream.end(); // 关闭流
// fs.rmdirSync(fileChunkDir); // 删除分片目录--留下来,可以看上传记录
res.send("文件合并完成");
}); app.listen(5000, () => {
console.log("服务器已启动:http://localhost:5000");
});

总结

通过上述代码,您可以实现大文件的分片上传和断点续传功能。这种方法不仅提高了上传的可靠性,还能有效应对网络的不稳定性。希望这篇文章对您有所帮助!

大文件传输与断点续传实现(极简Demo: React+Node.js)的更多相关文章

  1. WCF大文件传输【转】

    http://www.cnblogs.com/happygx/archive/2013/10/29/3393973.html WCF大文件传输 WCF传输文件的时候可以设置每次文件的传输大小,如果是小 ...

  2. 大文件传输 分片上传 上传id 分片号 授权给第三方上传

    https://www.zhihu.com/question/39593108 作者:ZeroOne链接:https://www.zhihu.com/question/39593108/answer/ ...

  3. WCF大文件传输服务

    由于项目需要,自己写一个基于WCF的大文件传输服务雏形.觉得有一定的参考价值,因此放在网上分享. 目前版本为v1.1特点如下: 1.文件传输端口为18650 2.上传和下载文件 3.支持获取文件传输状 ...

  4. Asp.net mvc 大文件上传 断点续传

    Asp.net mvc 大文件上传 断点续传 进度条   概述 项目中需要一个上传200M-500M的文件大小的功能,需要断点续传.上传性能稳定.突破asp.net上传限制.一开始看到51CTO上的这 ...

  5. 转:wcf大文件传输解决之道(2)

    此篇文章主要是基于http协议应用于大文件传输中的应用,现在我们先解析下wcf中编码器的定义,编码器实现了类的编码,并负责将Message内存中消息转变为网络发送的字节流或者字节缓冲区(对于发送方而言 ...

  6. 转:wcf大文件传输解决之道(1)

    首先声明,文章思路源于MSDN中徐长龙老师的课程整理,加上自己的一些心得体会,先总结如下: 在应对与大文件传输的情况下,因为wcf默认采用的是缓存加载对象,也就是说将文件包一次性接受至缓存中,然后生成 ...

  7. 利用Socket进行大文件传输

    分类: WINDOWS 最近接触到利用socket进行大文件传输的技术,有些心得,与大家分享.首先看看这个过程是怎么进行的(如下图):      所以,我们需要三个socket在窗体加载的时候初始化: ...

  8. AetherUpload大文件传输

    AetherUpload-Laravel是laravel框架下的一个大文件传输组件 github:https://github.com/peinhu/AetherUpload-Laravel 文件传输 ...

  9. 基于WCF的支持跨局域网可断点续传的大文件传输服务实现

    题外话:这个系列的文章记录了本人最近写的一个小工程,主要包含了两个功能,一是对文件的断点续传的功能,二是基于WCF的一对多文件主动发送的功能,顺便这也是我自己在WCF学习路上的一个小成果吧. 在网上找 ...

  10. .net大文件传输断点续传源码

    IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头. 一. 两个必要响应头Accept-Ranges.ETag 客户端每次提交下载请求时,服务 ...

随机推荐

  1. Vue 3 + Vite + SuerMap iClient构建报错Uncaught TypeError utils.inherits is not a function

    一.现象 Uncaught TypeError: utils.inherits is not a function 二.问题产生原因 Elasticsearch本身就需要这些东西,以前没有问题是因为W ...

  2. 【USB3.0协议学习】Topic4·USB3.0的Port Connect State Machine和设备枚举

    上一节的文章[USB3.0协议学习]Topic2·USB3.0的LTSSM分析中我们详细分析了USB3.0协议中的链路训练状态机(LTSSM)的各状态和跳转条件,覆盖了所有LTSSM状态.本文我们将从 ...

  3. USB编码方式(NRZI)及时钟同步方式

    1.概述 在同步通讯系统中,两个设备通讯则需要同步信号,同步信号分为时钟同步信号和自同步信号两种,时钟同步方式在通讯链路上具有时钟信号(IIC.SPI),自同步方式在通讯链路中没有同步信号(PCIE. ...

  4. kdump

    Kdump简单介绍 什么是Kdump? Kdump是在系统崩溃.死锁或死机时用来转储内存运行参数的一个工具和服务,是一种新的crash dump捕获机制,用来捕获kernel crash(内核崩溃)的 ...

  5. rancher发布nacos server docker 失败

    使用rancher发布nacos server 时报错 进入镜像查看日志发现报错No DataSource set 检查了好几遍环境变量已经全都配了,最后发现在nohup.out文件中指出没有找到na ...

  6. Tarjan缩点题单 刷题题解

    Tarjan缩点可以将一个图的每个强连通分量缩成一个点,然后构建新图,该图就会变成一个有向无环图.变成有向无环图之后就能结合最短路,拓扑......解决相应题目 洛谷题单分享: https://www ...

  7. Js数组&高阶函数

    数组也是一种复合数据类型,在数组可以存储多个不同类型的数据 数组中存储的是有序的数据,数组中的每个数据都有一个唯一的索引可以通过索引来操作获取数据 数组中存储的数据叫做元素 任何类型的值都可以成为数组 ...

  8. 自建家庭 KTV,在家想嗨就嗨

    现在用户最多.曲库最多的 K 歌软件是全民K歌,基本上想唱的歌都有,而且基本上每首歌都有 MV 或视频,使用体验也还不错,但是收费太贵了,对于一个月唱不了几次的打工人来说,唱一首歌就是"天价 ...

  9. Top100题(上)

    Top100(上) 散列 1. 两数之和 struct MyListNode { int val; int pos; struct MyListNode *next; }; // 散列表 typede ...

  10. F450 APM2.8 自组无人机手记

    由于是初次接触无人机,外加自组需要焊接,做了一些前期的心理建设.但是过程还是异常艰难.(不过,实际操作也就焊20个焊点左右,基本就组装起来了,操作并不复杂) 自组APM无人机是想学习Ardupilot ...