MST
星途 面试题库

面试题:React 实现大文件分片上传及断点续传

假设你需要在 React 应用中实现大文件的分片上传和断点续传功能,使用 HTML5 的 File API 和 Fetch API 等技术,请详细描述实现思路,包括如何进行文件分片、记录断点信息以及如何在中断后恢复上传。
33.9万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试
  1. 文件分片
    • 使用 File API 中的 File.prototype.slice 方法来对大文件进行分片。例如:
    const file = document.getElementById('fileInput').files[0];
    const chunkSize = 1024 * 1024; // 1MB 每片
    const totalChunks = Math.ceil(file.size / chunkSize);
    const chunks = [];
    for (let i = 0; i < totalChunks; i++) {
        const start = i * chunkSize;
        const end = Math.min(start + chunkSize, file.size);
        const chunk = file.slice(start, end);
        chunks.push(chunk);
    }
    
  2. 记录断点信息
    • 在客户端,我们可以维护一个状态对象来记录上传进度。例如,在 React 组件的 state 中:
    this.state = {
        uploadedChunks: [],
        currentChunkIndex: 0
    };
    
    • 当每一个分片成功上传后,将其索引添加到 uploadedChunks 数组中。
    • 对于服务器端,每次成功接收一个分片后,可以将已接收的分片信息记录在数据库中,比如使用 MongoDB 的文档存储每个文件已上传的分片序号等信息。
  3. 断点续传
    • 客户端
      • 在重新开始上传时,检查 state 中的 uploadedChunks 数组,从上次中断的位置开始上传。例如:
      const resumeUpload = () => {
          const { uploadedChunks, currentChunkIndex } = this.state;
          for (let i = currentChunkIndex; i < chunks.length; i++) {
              if (!uploadedChunks.includes(i)) {
                  const chunk = chunks[i];
                  // 这里使用 Fetch API 上传分片
                  fetch('/upload', {
                      method: 'POST',
                      body: chunk,
                      headers: {
                          'Content-Type': 'application/octet-stream',
                          'X-File-Name': file.name,
                          'X-Chunk-Index': i
                      }
                  })
                 .then(response => response.json())
                 .then(data => {
                      if (data.success) {
                          this.setState(prevState => ({
                              uploadedChunks: [...prevState.uploadedChunks, i],
                              currentChunkIndex: i + 1
                          }));
                      } else {
                          // 处理上传失败情况
                      }
                  });
              }
          }
      };
      
    • 服务器端
      • 在接收上传请求时,根据请求头中的 X-File-NameX-Chunk-Index 来判断该分片是否已上传。如果已上传,则跳过;如果未上传,则处理该分片的上传逻辑。例如在 Node.js 中使用 Express:
      const express = require('express');
      const app = express();
      const bodyParser = require('body-parser');
      app.use(bodyParser.raw({ type: 'application/octet-stream' }));
      app.post('/upload', (req, res) => {
          const fileName = req.get('X-File-Name');
          const chunkIndex = parseInt(req.get('X-Chunk-Index'));
          // 这里从数据库检查该分片是否已上传
          // 假设这里有一个函数 checkChunkUploaded 来检查
          if (checkChunkUploaded(fileName, chunkIndex)) {
              return res.json({ success: true });
          }
          // 处理上传逻辑,保存分片到文件等
          // 假设这里有一个函数 saveChunk 来保存分片
          saveChunk(req.body, fileName, chunkIndex);
          res.json({ success: true });
      });