0

0

如何用Node.js实现一个支持断点续传的文件上传?

夢幻星辰

夢幻星辰

发布时间:2025-10-10 23:11:01

|

380人浏览过

|

来源于php中文网

原创

实现断点续传需前后端协同:前端切片并记录上传状态,后端存储分片并支持查询与合并;通过文件哈希标识唯一性,上传前检查已传分片以跳过重传,最后按序合并并清理临时文件。

如何用node.js实现一个支持断点续传的文件上传?

实现支持断点续传的文件上传,核心在于将大文件分片上传,并记录已上传的片段信息,以便在网络中断或上传失败后能从中断处继续上传。Node.js结合前端可以很好地实现这一功能。以下是完整的实现思路和步骤。

1. 前端:文件切片与分片上传

用户选择文件后,前端将其切分为多个小块(chunk),并逐个上传。每个分片携带唯一标识(如文件名、文件哈希、分片序号等)。

示例代码(前端):

计算文件哈希(可选,用于唯一标识文件): 可使用 spark-md5FileReader 读取文件部分内容生成哈希。

切片上传逻辑:

  • 读取文件,使用 File.slice() 方法切割成固定大小的块(如 1MB)
  • 每块通过 POST 请求发送到服务器,附带参数:文件名、分片索引、总分片数、文件哈希等
  • 上传前可先请求服务器查询已上传的分片,跳过已上传的部分
  • 所有分片上传完成后,发送合并请求

2. 后端(Node.js):接收分片并存储

使用 Express 搭建服务,处理分片上传、状态查询和文件合并。

商易多用户商城
商易多用户商城

功能介绍:1. 商品出售包含拍卖模式,一口价模式。2. 全套系统采用淘宝网风格,成熟,简洁大方3. 每个商品支持多张图片上传,可自由设定,满足广大网民的迫切要求4. 商品信息支持 ubb,图文并茂5. 注册用户可参与竞拍,或者拍卖自己的商品6. 拥有会员注册,交易提醒,成交商品确认等邮件发送功能7. 拥有交易双方信用评价的功能,使得交易安全可*,可信度高8. 拥有安全稳定的用户虚拟币平台,可实现商

下载
所需依赖:

expressmulter(处理 multipart/form-data)、fspath

关键接口设计:
  • /upload/check:查询某文件已上传的分片列表
  • /upload/chunk:接收单个分片,保存到临时目录
  • /upload/merge:所有分片上传完成后,合并文件

示例代码(Node.js 后端):

const express = require('express');
const multer = require('multer');
const fs = require('fs');
const path = require('path');

const app = express();
const uploadDir = './uploads';
const chunkDir = './chunks';

!fs.existsSync(uploadDir) && fs.mkdirSync(uploadDir);
!fs.existsSync(chunkDir) && fs.mkdirSync(chunkDir);

// 配置 multer 存储分片
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    const dir = path.join(chunkDir, req.body.fileHash);
    !fs.existsSync(dir) && fs.mkdirSync(dir, { recursive: true });
    cb(null, dir);
  },
  filename: (req, file, cb) => {
    // 使用分片索引命名
    cb(null, `part-${req.body.chunkIndex}`);
  }
});
const upload = multer({ storage });

// 查询已上传的分片
app.post('/upload/check', (req, res) => {
  const { fileHash } = req.body;
  const chunkPath = path.join(chunkDir, fileHash);
  if (!fs.existsSync(chunkPath)) return res.json({ uploaded: [] });

  fs.readdir(chunkPath, (err, files) => {
    if (err) return res.status(500).send();
    const uploaded = files.map(f => parseInt(f.split('-')[1]));
    res.json({ uploaded });
  });
});

// 接收分片
app.post('/upload/chunk', upload.single('chunk'), (req, res) => {
  res.json({ success: true });
});

// 合并文件
app.post('/upload/merge', (req, res) => {
  const { fileHash, fileName, totalChunks } = req.body;
  const chunkPath = path.join(chunkDir, fileHash);
  const filePath = path.join(uploadDir, fileName);

  const writeStream = fs.createWriteStream(filePath);

  function appendChunk(i) {
    if (i >= totalChunks) {
      writeStream.end();
      // 清理分片
      fs.rm(chunkPath, { recursive: true }, () => {});
      return res.json({ url: `/files/${fileName}` });
    }
    const partPath = path.join(chunkPath, `part-${i}`);
    const readStream = fs.createReadStream(partPath);
    readStream.pipe(writeStream, { end: false });
    readStream.on('end', () => appendChunk(i + 1));
  }

  appendChunk(0);
});

3. 断点续传的关键逻辑

要真正实现“续传”,需满足以下几点:

  • 唯一标识文件:使用文件名 + 大小 + 哈希值确保文件唯一性
  • 上传前检查:上传开始前调用 /upload/check 获取已上传的分片,跳过重传
  • 按序存储分片:每个分片以索引命名,便于后续合并
  • 合并后清理临时文件:防止磁盘占用

4. 前端优化建议

  • 使用 Web Workers 计算大文件哈希,避免阻塞 UI
  • 添加上传进度条:基于已上传分片数量 / 总数
  • 支持暂停/恢复:暂停时停止发送,恢复时重新 check 并继续
  • 错误重试机制:对失败的分片进行有限次重试
基本上就这些。核心是前后端协同管理分片状态,Node.js 负责接收、存储和合并,前端负责切片和流程控制。不复杂但容易忽略细节,比如文件哈希一致性、并发写入等问题。

相关专题

更多
硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

980

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

38

2025.10.17

go语言 数组和切片
go语言 数组和切片

本专题整合了go语言数组和切片的区别与含义,阅读专题下面的文章了解更多详细内容。

43

2025.09.03

js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

505

2023.06.20

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

240

2023.07.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

246

2023.08.03

js是什么意思
js是什么意思

JS是JavaScript的缩写,它是一种广泛应用于网页开发的脚本语言。JavaScript是一种解释性的、基于对象和事件驱动的编程语言,通常用于为网页增加交互性和动态性。它可以在网页上实现复杂的功能和效果,如表单验证、页面元素操作、动画效果、数据交互等。

5198

2023.08.17

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

470

2023.09.01

苹果官网入口直接访问
苹果官网入口直接访问

苹果官网直接访问入口是https://www.apple.com/cn/,该页面具备0.8秒首屏渲染、HTTP/3与Brotli加速、WebP+AVIF双格式图片、免登录浏览全参数等特性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

10

2025.12.24

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 8万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号