大文件断点续传

需要开发一个网页应用,用于用户上传大文件。考虑到可能的网络中断,我们希望实现断点续传功能,使得上传过程能从中断处恢复。

需求分析

  • 前端:切割文件为小块,逐块上传,记录上传状态。
  • 后端:支持分块上传的处理逻辑,记录上传进度以便恢复。
  • 安全性:保证上传文件的完整性和安全性。

技术选择

  • 前端:JavaScript (可使用 React/Vue 等框架),Fetch API。
  • 后端:Node.js 和 Express.js 作为服务器框架,配合数据库存储上传状态。

前端实现

1. 分块上传

文件被分割成多个块,每块上传并记录状态:

javascript 复制代码
javascriptconst CHUNK_SIZE = 2 * 1024 * 1024; // 每块2MB
const API_URL = 'http://localhost:3000/upload';

function splitFile(file) {
  const chunks = [];
  let start = 0;

  while (start < file.size) {
    const end = Math.min(start + CHUNK_SIZE, file.size);
    chunks.push({ blob: file.slice(start, end), number: chunks.length });
    start += CHUNK_SIZE;
  }

  return chunks;
}

async function uploadFile(file) {
  const chunks = splitFile(file);
  const lastUploadedChunk = await getUploadedChunkNumber(file.name);

  for (const chunk of chunks.slice(lastUploadedChunk + 1)) {
    await uploadChunk(chunk.blob, chunk.number, file.name);
  }

  console.log('File upload complete');
}

async function uploadChunk(chunkBlob, chunkNumber, fileName) {
  const formData = new FormData();
  formData.append('chunk', chunkBlob);
  formData.append('chunkNumber', chunkNumber);
  formData.append('fileName', fileName);

  try {
    await fetch(API_URL, { method: 'POST', body: formData });
    console.log(`Chunk ${chunkNumber} uploaded`);
  } catch (error) {
    console.error(`Failed to upload chunk ${chunkNumber}`, error);
  }
}

async function getUploadedChunkNumber(fileName) {
  const response = await fetch(`${API_URL}/status?fileName=${fileName}`);
  const { lastChunkNumber } = await response.json();
  return lastChunkNumber || -1;
}

后端实现

使用 Node.js 和 Express.js 搭建服务器,处理块上传请求并记录状态。

ini 复制代码
javascriptconst express = require('express');
const cors = require('cors');
const fs = require('fs');
const path = require('path');

const app = express();
const UPLOAD_DIR = path.join(__dirname, 'uploads');

app.use(cors());
app.use(express.urlencoded({ extended: true }));
app.use(express.json());

app.post('/upload', (req, res) => {
  const { chunkNumber, fileName } = req.body;
  const filePath = path.join(UPLOAD_DIR, fileName);

  const writeStream = fs.createWriteStream(filePath, {
    flags: 'a',
  });

  req.pipe(writeStream);

  writeStream.on('close', () => {
    updateChunkStatus(fileName, chunkNumber);
    res.sendStatus(200);
  });

  writeStream.on('error', () => {
    res.sendStatus(500);
  });
});

app.get('/upload/status', (req, res) => {
  const { fileName } = req.query;
  const lastChunkNumber = getLastUploadedChunk(fileName);
  res.json({ lastChunkNumber });
});

function updateChunkStatus(fileName, chunkNumber) {
  // Assume we use a database or JSON file to store uploaded status
  // Simulated here with a simple JSON file approach
  const statusFile = path.join(UPLOAD_DIR, `${fileName}.json`);
  let status = {};

  if (fs.existsSync(statusFile)) {
    status = JSON.parse(fs.readFileSync(statusFile));
  }

  status[fileName] = chunkNumber;
  fs.writeFileSync(statusFile, JSON.stringify(status));
}

function getLastUploadedChunk(fileName) {
  const statusFile = path.join(UPLOAD_DIR, `${fileName}.json`);
  if (fs.existsSync(statusFile)) {
    const status = JSON.parse(fs.readFileSync(statusFile));
    return status[fileName] || -1;
  }
  return -1;
}

app.listen(3000, () => console.log('Server started on port 3000'));

注意事项

  • 文件完整性:确保所有块按正确顺序合并,必要时进行校验。
  • 错误处理和重试机制:在传输失败时,提供重试或处理错误的机制。
  • 安全性:验证用户权限及完整性以防止恶意上传。

通过这种方式,我们实现了一个基本断点续传的系统,适合用例中大文件上传的需求。该系统提供了简单但有效的解决方案来处理网络中断和提升用户体验。

相关推荐
用户130874105732几秒前
SSE技术详解:实现服务器到客户端的实时数据推送
前端
Mintopia2 分钟前
计算机图形学微平面理论:微观世界的光影魔术
前端·javascript·计算机图形学
北辰alk2 分钟前
深入解析 core-js:现代 JavaScript 的兼容性基石
前端
不想当reducer4 分钟前
React Native 阿里云 OSS 上传实战:从相册资源处理到动态签名管理
前端·javascript·react native
大爱仙尊古月方源4 分钟前
基于Vue3 + Element Plus Tree-v2 虚拟树组件封装开发记录
前端·vue.js
低代码布道师7 分钟前
第八部分:阶段项目 6:构建 React 前端应用
前端·react.js·前端框架
杏仁海棠花饼8 分钟前
Vue3(ref与reactive)
前端·学习
菥菥爱嘻嘻8 分钟前
React---扩展补充
前端·react.js·前端框架
NoneCoder10 分钟前
React 性能监控与错误上报
前端·react.js·面试·前端框架
前端_Danny10 分钟前
从Node.js到React/Vue3:流式输出技术的全栈实现指南
前端·react.js·node.js