React前端开发中实现断点续传

在前端开发中,断点续传是指在上传文件时,如果上传过程中中断(如网络断开、页面刷新等),可以从断点处继续上传,而不是重新上传整个文件。这种功能在大文件上传场景中非常有用。

以下是实现断点续传的思路和具体步骤:

实现思路

文件分片:

将大文件分割成多个小文件块(chunk)。

每个文件块单独上传。

记录上传进度:

使用本地存储(如 localStorage)或服务端记录已上传的文件块。

断点续传:

在上传前检查已上传的文件块,跳过已上传的部分。

从未上传的部分开始继续上传。

合并文件:

所有文件块上传完成后,通知服务端合并文件。

实现步骤

1. 前端实现

以下是基于 React 和 Axios 的断点续传实现示例:

css 复制代码
import React, { useState, useRef } from "react";
import axios from "axios";

const chunkSize = 1024 * 1024; // 每个文件块的大小(1MB)

const FileUpload = () => {
  const [file, setFile] = useState(null);
  const [progress, setProgress] = useState(0);
  const fileInputRef = useRef(null);

  // 处理文件选择
  const handleFileChange = (e) => {
    const selectedFile = e.target.files[0];
    setFile(selectedFile);
  };

  // 上传文件
  const handleUpload = async () => {
    if (!file) return;

    const totalChunks = Math.ceil(file.size / chunkSize); // 总文件块数
    let uploadedChunks = 0; // 已上传的文件块数

    // 检查已上传的文件块
    const uploadedChunksFromStorage = JSON.parse(
      localStorage.getItem(file.name) || []
    );

    for (let i = 0; i < totalChunks; i++) {
      // 如果当前文件块已上传,跳过
      if (uploadedChunksFromStorage.includes(i)) continue;

      const start = i * chunkSize;
      const end = Math.min(start + chunkSize, file.size);
      const chunk = file.slice(start, end); // 获取文件块

      const formData = new FormData();
      formData.append("file", chunk);
      formData.append("fileName", file.name);
      formData.append("chunkIndex", i);
      formData.append("totalChunks", totalChunks);

      try {
        await axios.post("/upload", formData, {
          headers: { "Content-Type": "multipart/form-data" },
        });

        // 更新已上传的文件块
        uploadedChunksFromStorage.push(i);
        localStorage.setItem(file.name, JSON.stringify(uploadedChunksFromStorage));

        // 更新上传进度
        uploadedChunks++;
        setProgress(Math.round((uploadedChunks / totalChunks) * 100));
      } catch (error) {
        console.error("上传失败", error);
        return;
      }
    }

    // 所有文件块上传完成后,通知服务端合并文件
    try {
      await axios.post("/merge", { fileName: file.name });
      alert("上传完成");
      localStorage.removeItem(file.name); // 清除本地存储的上传记录
      setProgress(0);
      fileInputRef.current.value = ""; // 清空文件输入
    } catch (error) {
      console.error("文件合并失败", error);
    }
  };

  return (
    <div>
      <h1>文件断点续传</h1>
      <input type="file" onChange={handleFileChange} ref={fileInputRef} />
      <button onClick={handleUpload}>上传</button>
      <div>上传进度: {progress}%</div>
    </div>
  );
};

export default FileUpload;

2. 服务端实现

服务端需要支持文件块的上传和合并。以下是一个简单的 Node.js 实现示例:

css 复制代码
const express = require("express");
const multer = require("multer");
const fs = require("fs");
const path = require("path");

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

// 上传文件块
app.post("/upload", upload.single("file"), (req, res) => {
  const { fileName, chunkIndex } = req.body;
  const chunkPath = path.join("uploads", `${fileName}-${chunkIndex}`);

  // 将文件块保存到临时目录
  fs.renameSync(req.file.path, chunkPath);

  res.send({ message: "文件块上传成功" });
});

// 合并文件块
app.post("/merge", (req, res) => {
  const { fileName } = req.body;
  const chunksDir = path.join("uploads");
  const chunks = fs
    .readdirSync(chunksDir)
    .filter((file) => file.startsWith(fileName))
    .sort((a, b) => a.split("-")[1] - b.split("-")[1]);

  // 创建可写流
  const writeStream = fs.createWriteStream(path.join("uploads", fileName));

  // 合并文件块
  chunks.forEach((chunk) => {
    const chunkPath = path.join(chunksDir, chunk);
    const readStream = fs.createReadStream(chunkPath);
    readStream.pipe(writeStream, { end: false });
    readStream.on("end", () => {
      fs.unlinkSync(chunkPath); // 删除已合并的文件块
    });
  });

  writeStream.on("finish", () => {
    res.send({ message: "文件合并成功" });
  });
});

app.listen(3000, () => {
  console.log("服务端运行在 http://localhost:3000");
});

关键点解析

文件分片:

使用 File.slice() 方法将文件分割成多个块。

每个块单独上传。

记录上传进度:

使用 localStorage 记录已上传的文件块索引。

上传前检查已上传的文件块,跳过已上传的部分。

断点续传:

如果上传中断,重新上传时从未上传的文件块开始。

合并文件:

所有文件块上传完成后,通知服务端合并文件。

服务端按顺序读取文件块并写入目标文件。

相关推荐
QQ1__8115175154 小时前
Spring boot名城小区物业管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
前端·vue.js·spring boot
钛态4 小时前
前端微前端架构:大项目的救命稻草还是自找麻烦?
前端·vue·react·web
一粒黑子4 小时前
【实战解析】阿里开源 PageAgent:纯前端 GUI Agent,一行JS让网页支持自然语言操控
前端·javascript·开源
独角鲸网络安全实验室5 小时前
2026微信小程序抓包全解析:从实操落地到合规风控,解锁前端调试新范式
前端·微信小程序·小程序·抓包·系统代理绕过·https证书严格校验·进程隔离
紫微AI5 小时前
前端文本测量成了卡死一切创新的最后瓶颈,pretext实现突破了
前端·人工智能·typescript
GISer_Jing5 小时前
AI前端(From豆包)
前端·aigc·ai编程
IT枫斗者5 小时前
前端部署后如何判断“页面是不是最新”?一套可落地的版本检测方案(适配 Vite/Vue/React/任意 SPA)
前端·javascript·vue.js·react.js·架构·bug
测试修炼手册5 小时前
[测试技术] 深入理解 JSON Web Token (JWT)
前端·json
AI老李5 小时前
2026 年 Web 前端开发的 8 个趋势!
前端
里欧跑得慢5 小时前
15. Web可访问性最佳实践:让每个用户都能平等访问
前端·css·flutter·web