返回

实现 Node.js 大文件断点续传:分块上传、文件合并和容错机制

前端

引言

文件上传是大规模应用程序中一个常见的需求。然而,当处理大文件时,断点续传机制就显得至关重要,它允许用户在网络中断或其他错误发生后继续上传。

分块上传和合并

为了有效地处理大文件,我们采用分块上传的方法。将文件分成较小的块,并分别上传这些块。服务器接收块并将其存储在临时位置。一旦所有块都上传完毕,服务器将它们合并为一个完整的文件。

容错机制

为了提高可靠性,我们实施了容错机制。如果上传过程中发生错误,服务器将尝试重新上传失败的块。我们还使用 ETags 和 Last-Modified 头来确保只有尚未上传的块才会被重新上传。

技术选型

  • Node.js: 服务器端框架
  • Express: Node.js 框架
  • Multer: 处理文件上传
  • Axios: 处理 HTTP 请求

前端实现

前端代码负责将文件分块并通过 Axios 将其发送到服务器。

const chunkSize = 1024 * 1024; // 1MB

function chunkFile(file) {
  const chunks = [];
  let start = 0;
  while (start < file.size) {
    const end = Math.min(start + chunkSize, file.size);
    chunks.push(file.slice(start, end));
    start += chunkSize;
  }
  return chunks;
}

function uploadChunk(chunk, index, file) {
  // 使用 Axios 发送块到服务器
}

后端实现

后端代码负责接收块、存储它们并合并文件。

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

const app = express();
const upload = multer({ dest: 'uploads/' });

app.post('/upload', upload.single('file'), async (req, res) => {
  const file = req.file;
  // 获取文件块索引
  const index = parseInt(req.query.index);

  // 将块保存到临时位置
  const tempFilePath = `uploads/${file.filename}_${index}`;
  fs.writeFileSync(tempFilePath, req.body);

  // 如果这是最后一个块,则合并文件
  if (index === file.chunks - 1) {
    // 合并块
    const chunks = [];
    for (let i = 0; i < file.chunks; i++) {
      const chunkPath = `uploads/${file.filename}_${i}`;
      chunks.push(fs.readFileSync(chunkPath));
    }
    const mergedFile = Buffer.concat(chunks);

    // 删除临时块
    fs.unlinkSync(`uploads/${file.filename}_${index}`);

    // 保存合并文件
    fs.writeFileSync(`uploads/${file.originalname}`, mergedFile);

    // 发送成功响应
    res.json({ success: true });
  } else {
    // 发送继续上传响应
    res.json({ success: true, continue: true });
  }
});

示例代码

完整的示例代码可以在 GitHub 上找到。

结论

通过分块上传、文件合并和容错机制,我们创建了一个健壮且高效的大文件断点续传解决方案。这种解决方案消除了大文件上传的挑战,提高了应用程序的可靠性。