跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScript大前端

前端文件上传方案:分片上传与断点续传实战

探讨了前端文件上传的优化方案,指出原生 input type=file 在处理大文件时的性能瓶颈。介绍了分片上传、断点续传和拖拽上传三种主流实现方式,并提供了基于 JavaScript 和 React 的代码示例。同时总结了上传优化策略,包括并发控制、进度显示及文件类型检查等最佳实践,旨在提升用户体验和上传稳定性。

CodeArtist发布于 2026/4/6更新于 2026/9/563 浏览
前端文件上传方案:分片上传与断点续传实战

前端文件上传方案概述

为什么需要优化文件上传

原生 input 标签在处理大文件时存在明显局限,例如上传 100MB 的文件可能导致浏览器卡死且无进度提示。为了提升用户体验和传输稳定性,需要采用更完善的上传方案。

原生上传示例
<!-- 反面教材:原生文件上传 -->
<input type="file" onchange="uploadFile(this.files[0])" />
<script>
function uploadFile(file) {
  const formData = new FormData();
  formData.append('file', file);
  // 直接上传,没有进度,没有断点续传
  fetch('/api/upload', {
    method: 'POST',
    body: formData
  });
}
</script>

核心实现方案

1. 分片上传

将大文件切割成多个小块并发或顺序上传,降低单次请求压力并支持进度追踪。

// 正确姿势:分片上传
class ChunkUploader {
  constructor(file, options = {}) {
    this.file = file;
    this.chunkSize = options.chunkSize || 1024 * 1024; // 1MB
    this.chunks = Math.ceil(file.size / this.chunkSize);
    this.uploadedChunks = 0;
  }

  async upload() {
    const promises = [];
    for (let i = 0; i < this.chunks; i++) {
      const start = i * this.chunkSize;
      const end = Math.min(start + this.chunkSize, this.file.size);
      const chunk = this.file.slice(start, end);
      promises.push(this.uploadChunk(chunk, i));
    }
    await Promise.all(promises);
    await this.mergeChunks();
  }

  async uploadChunk(chunk, index) {
    const formData = new FormData();
    formData.append('chunk', chunk);
    formData.append('index', index);
    formData.append('total', this.chunks);
    formData.append('filename', this.file.name);
    await fetch('/api/upload/chunk', {
      method: 'POST',
      body: formData
    });
    this.uploadedChunks++;
    this.onProgress(this.uploadedChunks / this.chunks);
  }

  onProgress(progress) {
    console.log(`上传进度:${(progress * 100).toFixed(2)}%`);
  }

  async mergeChunks() {
    await fetch('/api/upload/merge', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ filename: this.file.name, chunks: this.chunks })
    });
  }
}

// 使用
const uploader = new ChunkUploader(file, { chunkSize: 1024 * 1024 });
uploader.upload();
2. 断点续传

记录已上传的分片索引,网络中断后可从上次位置继续,避免重复传输。

// 正确姿势:断点续传
class ResumableUploader {
  constructor(file) {
    this.file = file;
    this.chunkSize = 1024 * 1024;
    this.uploadedChunks = new Set();
  }

  async init() {
    // 获取已上传的分片
    const response = await fetch(`/api/upload/status?filename=${this.file.name}`);
    const { uploadedChunks } = await response.json();
    this.uploadedChunks = new Set(uploadedChunks);
  }

  async upload() {
    const chunks = Math.ceil(this.file.size / this.chunkSize);
    for (let i = 0; i < chunks; i++) {
      if (this.uploadedChunks.has(i)) {
        console.log(`分片${i}已上传,跳过`);
        continue;
      }
      const start = i * this.chunkSize;
      const end = Math.min(start + this.chunkSize, this.file.size);
      const chunk = this.file.slice(start, end);
      await this.uploadChunk(chunk, i);
      this.uploadedChunks.add(i);
      localStorage.setItem('uploadProgress', JSON.stringify([...this.uploadedChunks]));
    }
    await this.mergeChunks();
    localStorage.removeItem('uploadProgress');
  }

  async uploadChunk(chunk, index) {
    // 上传逻辑...
  }
}
3. 拖拽上传

利用 HTML5 Drag and Drop API 提供直观的文件选择体验,结合 React Hooks 实现组件化。

// 正确姿势:拖拽上传
import { useCallback } from 'react';

function DragUpload({ onUpload }) {
  const handleDrop = useCallback((e) => {
    e.preventDefault();
    const files = Array.from(e.dataTransfer.files);
    files.forEach(file => onUpload(file));
  }, [onUpload]);

  const handleDragOver = useCallback((e) => {
    e.preventDefault();
  }, []);

  return (
    <div className="drag-upload" onDrop={handleDrop} onDragOver={handleDragOver}>
      <p>拖拽文件到此处上传</p>
      <input type="file" multiple onChange={(e) => {
        Array.from(e.target.files).forEach(file => onUpload(file));
      }} />
    </div>
  );
}

实战技巧:文件上传指南

1. 上传优化策略
  1. 分片上传:大文件切分上传,提高成功率。
  2. 断点续传:支持暂停恢复,节省流量和时间。
  3. 并发控制:限制同时上传数量,防止阻塞主线程。
  4. 进度显示:实时显示上传进度条,提升用户感知。
2. 最佳实践
// ✅ 显示上传进度
const xhr = new XMLHttpRequest();
xhr.upload.onprogress = (e) => {
  const progress = (e.loaded / e.total) * 100;
  console.log(`${progress}%`);
};

// ✅ 图片预览
const preview = URL.createObjectURL(file);

// ✅ 文件类型检查
const allowedTypes = ['image/jpeg', 'image/png'];
if (!allowedTypes.includes(file.type)) {
  alert('不支持的文件类型');
  return;
}

总结

文件上传是用户体验的关键环节。通过分片、断点续传及拖拽等优化手段,可以显著提升上传效率和专业度,避免原生 input 带来的性能瓶颈。

目录

  1. 前端文件上传方案概述
  2. 为什么需要优化文件上传
  3. 原生上传示例
  4. 核心实现方案
  5. 1. 分片上传
  6. 2. 断点续传
  7. 3. 拖拽上传
  8. 实战技巧:文件上传指南
  9. 1. 上传优化策略
  10. 2. 最佳实践
  11. 总结

更多推荐文章

查看全部
  • 视频修复技术解析:使用 Python 修复损坏 MP4 文件的三种方案
  • iOS 26 系统兼容适配:UITabBar 液态玻璃效果与 WiFi SSID 获取
  • Linux C++ 多线程编程入门:从核心概念到常用函数详解
  • OpenClaw 集成 GitHub Copilot GPT-5.4 修复方案
  • 荣耀发布 Robot Phone 与人形机器人 ROBOT,探索 AI 硬件生态
  • 树莓派 5 部署冬瓜 HAOS:智能家居中枢搭建指南
  • Spring Boot Starter 自定义开发实战:构建企业级组件库
  • Spring AI 实战指南:核心接口、消息类型与流式输出详解
  • 国内主流大模型盘点:优缺点分析与行业应用现状
  • 昇腾 NPU 部署 Llama 2 模型性能测试与优化
  • Flutter 2 跨平台开发实战指南:从基础到进阶
  • C++ 异常处理机制详解:错误码对比、抛出捕获与安全原则
  • 国内大模型企业面试复盘与经验总结
  • 资深工程师的 Web 前端开发全维准备指南
  • OpenClaw 集成 QVeris 实现 AI 助手实时数据查询
  • SpringBoot 集成 MinIO 文件服务器配置与使用
  • C++ map 与 multimap 核心用法及底层原理
  • FLUX.1-DEV 模型低显存部署指南:基于 4bit 量化技术优化
  • 自学 Python 使用 PyCharm 是否友好及学习建议
  • 大语言模型训练指南:从基础概念到微调实战

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online