程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • 后端开发

  • 前端开发

    • 照片上传组件
    • localStorage工具类
    • sessionStorage工具类
    • 对话框组件
    • 消息提示工具类
    • 按钮组件
    • 前端文件上传
      • 一、前端文件上传的常见方式
        • 1. 使用 <form> 表单提交文件
        • 2. 使用原生 XMLHttpRequest 实现异步上传
        • 3. 使用 Axios 进行异步上传
        • 4. 多文件上传
        • 5. 大文件分片上传
        • 6. 使用第三方库进行大文件上传
      • 二、方式对比总结
      • 三、重要 API 和参数详解
    • 前端文件下载
    • 前端数据一致性
    • 后台管理系统组件
  • 开发笔记
  • 前端开发
scholar
2024-12-27
目录

前端文件上传

# 前端文件上传

文件上传在前端开发中是一个常见的需求,从基础的单文件上传到复杂的大文件分片上传,每种方式都有其适用的场景和实现方法。以下详细总结了前端文件上传的几种方式,包括使用原生 XMLHttpRequest、Axios 以及第三方库,并对比了它们的优缺点和适用场景。

# 一、前端文件上传的常见方式

# 1. 使用 <form> 表单提交文件

实现原理:

最传统的文件上传方式,使用 HTML 的 <form> 表单配合 <input type="file"> 提交文件。通过设置 enctype="multipart/form-data",表单可以将文件作为二进制数据上传到服务器。

实现步骤:

<form action="/api/upload" method="post" enctype="multipart/form-data">
  <!-- 文件输入框,用户选择文件 -->
  <input type="file" name="file" />
  <!-- 提交按钮 -->
  <button type="submit">上传文件</button>
</form>
1
2
3
4
5
6

关键点:

  • enctype="multipart/form-data":表单的编码类型,必须设置为 multipart/form-data 以支持文件上传。
  • method="post":上传文件通常使用 POST 请求,因为文件数据较大且复杂,GET 请求不适合。
  • <input type="file">:文件选择控件,允许用户选择本地文件。

优点:

  • 简单易用,无需额外引入 JavaScript 代码。
  • 兼容性好,适用于所有现代浏览器。

缺点:

  • 不能实现异步上传,页面会刷新,用户体验不佳。
  • 无法进行上传进度显示或其他高级控制。

适用场景:

  • 简单的文件上传场景,如表单提交中包含文件的情况。
  • 无需复杂交互和进度控制的低频上传场景。

# 2. 使用原生 XMLHttpRequest 实现异步上传

实现原理:

通过使用原生的 XMLHttpRequest (XHR) 对象,前端可以实现文件的异步上传,从而避免页面刷新,并可以更灵活地控制上传进度和响应处理。

实现步骤:

function uploadFile() {
  const fileInput = document.querySelector('input[type="file"]');
  const file = fileInput.files[0]; // 获取用户选择的文件

  const formData = new FormData(); // 使用 FormData 对象封装文件数据
  formData.append('file', file); // 将文件添加到 FormData 对象中

  const xhr = new XMLHttpRequest();
  xhr.open('POST', '/api/upload'); // 打开一个 POST 请求
  xhr.onload = function () {
    if (xhr.status === 200) {
      console.log('上传成功:', xhr.responseText); // 上传成功后的回调
    } else {
      console.error('上传失败:', xhr.statusText);
    }
  };
  xhr.upload.onprogress = function (event) { // 监听上传进度
    if (event.lengthComputable) {
      const percentComplete = (event.loaded / event.total) * 100;
      console.log('上传进度:', percentComplete + '%');
    }
  };
  xhr.send(formData); // 发送封装好的 FormData
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

关键点:

  • FormData 对象:用于构建表单数据,包括文件内容,可以自动设置请求头为 multipart/form-data,无需手动指定。
  • xhr.open('POST', '/api/upload'):指定上传的接口地址和请求方法。
  • xhr.upload.onprogress:用于监控文件上传的进度,event.loaded 和 event.total 提供了已上传和总大小的信息。

优点:

  • 支持异步上传,页面无需刷新,提高用户体验。
  • 可以精细控制上传进度、错误处理等细节。

缺点:

  • 代码相对复杂,需要处理跨域、进度显示等问题。
  • 只适合单文件上传,多文件上传需要额外处理。

适用场景:

  • 适用于需要更好用户体验的文件上传场景,如图片上传、文档上传。
  • 需要上传进度提示和结果反馈的场景。

# 3. 使用 Axios 进行异步上传

实现原理:

Axios 是一个基于 Promise 的 HTTP 客户端,提供了更简洁的 API,用于进行 HTTP 请求。使用 Axios 进行文件上传可以简化代码,并提供上传进度控制和更好的错误处理机制。

实现步骤:

function uploadFileWithAxios() {
  const fileInput = document.querySelector('input[type="file"]');
  const file = fileInput.files[0]; // 获取用户选择的文件

  const formData = new FormData(); // 使用 FormData 对象封装文件数据
  formData.append('file', file); // 将文件添加到 FormData 对象中

  // 使用 Axios 进行文件上传
  axios.post('/api/upload', formData, {
    headers: {
      'Content-Type': 'multipart/form-data' // 设置请求头,必须设置为 multipart/form-data
    },
    onUploadProgress: function (progressEvent) { // 监听上传进度
      const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
      console.log('上传进度:', percentCompleted + '%');
    }
  })
  .then(response => {
    console.log('上传成功:', response.data);
  })
  .catch(error => {
    console.error('上传失败:', error);
  });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

关键点:

  • headers: { 'Content-Type': 'multipart/form-data' }:虽然 Axios 会自动设置这个头部,但明确设置有助于理解请求的内容类型。
  • onUploadProgress:用于监听上传的进度,接收的 progressEvent 包含已上传字节和总字节数。

优点:

  • 封装了底层的 XMLHttpRequest,代码简洁且易读。
  • 提供了更好的错误处理和跨域支持。
  • 支持上传进度监控。

缺点:

  • 需要引入额外的库,对于简单场景可能增加了不必要的依赖。
  • 对比原生 XHR,灵活性稍差。

适用场景:

  • 适用于大多数现代 Web 应用程序的文件上传需求,尤其是需要上传进度监控和错误处理的场景。

# 4. 多文件上传

实现原理:

多文件上传是基于异步上传的扩展,通过设置 <input type="file" multiple> 属性,用户可以一次选择多个文件,然后通过循环处理每个文件并上传。

实现步骤:

function uploadMultipleFiles() {
  const fileInput = document.querySelector('input[type="file"]');
  const files = fileInput.files; // 获取多个文件

  const formData = new FormData();
  for (let i = 0; i < files.length; i++) {
    formData.append('files[]', files[i]); // 将每个文件添加到 FormData 对象中
  }

  axios.post('/api/uploadMultiple', formData, {
    headers: {
      'Content-Type': 'multipart/form-data' // 设置请求头,必须设置为 multipart/form-data
    }
  }).then(response => {
    console.log('上传成功:', response.data);
  }).catch(error => {
    console.error('上传失败:', error);
  });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

关键点:

  • <input type="file" multiple>:允许用户选择多个文件。
  • formData.append('files[]', files[i]):将每个文件逐一添加到 FormData 对象中,后端根据键名获取文件。

优点:

  • 支持批量上传,简化用户操作。
  • 结合 Axios 实现异步上传,灵活性强。

缺点:

  • 需要处理多个文件的上传进度和错误处理。
  • 如果文件较大,上传时间较长且难以管理。

适用场景:

  • 适用于需要一次性上传多个文件的场景,如图片批量上传。
  • 用户体验要求较高且需要实时反馈的场景。

# 5. 大文件分片上传

实现原理:

当上传大文件时,可能遇到网络不稳定、浏览器限制(如单次上传的文件大小)等问题,导致上传失败。分片上传通过将大文件拆分成多个小片段,每次上传一个片段,上传完成后在后端进行合并。这样可以提高上传的稳定性,并支持断点续传。

实现步骤:

  1. 前端将大文件切片:
function uploadLargeFile(file) {
  const chunkSize = 5 * 1024 * 1024; // 每片大小为 5MB
  const chunks = Math.ceil(file.size / chunkSize); // 计算总片数

  for (let i = 0; i < chunks; i++) {
    const chunk = file.slice(i * chunkSize, (i + 1) * chunkSize); // 切片
    const formData = new FormData();
    formData.append('file', chunk);
    formData.append('chunkIndex', i); // 片段索引
    formData.append('totalChunks', chunks); // 总片数
    formData.append('fileName', file.name); // 文件名称

    // 发送分片数据
    axios.post('/api/uploadChunk', formData).then(response => {
      console.log(`片段 ${i + 1}/${chunks} 上传成功`);
    }).catch(error => {
      console.error(`片段 ${i + 1}/${chunks} 上传失败`, error);
    });
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  1. 后端接收并合并分片:

后端会根据传递的片段信息,将所有分片进行合并,最终恢复成完整文件。

关键点:

  • file.slice():用于将大文件按指定大小切片。
  • chunkIndex:片段的索引,用于确定每个片段的顺序。
  • totalChunks:文件总片数,便于后端知道何时完成所有片段的接收。

优点:

  • 支持断点续传,失败后只需重新上传未完成的部分。
  • 提高上传大文件的稳定性,解决浏览器限制。

缺点:

  • 实现复杂,需要前后端配合处理分片和合并逻辑。
  • 上传时间较长,特别是在网络较差的情况下。

适用场景:

  • 适用于超大文件(如视频、压缩包)上传。
  • 对上传稳定性要求高的场景。

# 6. 使用第三方库进行大文件上传

实现原理:

针对大文件上传,存在一些第三方库专门用于处理分片上传、断点续传、进度监控等复杂场景。这些库通常封装了复杂的逻辑,简化了开发流程。

常用库:

  1. resumable.js (opens new window)

    • 支持文件分片上传、断点续传。
    • 自动处理网络中断后的重新上传。
    • 提供了对大文件上传的高级控制。
  2. fine-uploader (opens new window)

    • 强大的文件上传库,支持分片、重试、上传队列等功能。
    • 内置了丰富的 UI 组件,适合用户体验要求较高的项目。
  3. uppy (opens new window)

    • 功能全面的文件上传库,支持分片、断点续传、云端上传等。
    • 提供了灵活的插件系统,可以根据需求进行定制。

代码示例(使用 uppy):

import Uppy from '@uppy/core';
import XHRUpload from '@uppy/xhr-upload';

const uppy = Uppy({
  autoProceed: true,
  restrictions: {
    maxFileSize: 100 * 1024 * 1024, // 最大文件大小 100MB
    maxNumberOfFiles: 3, // 最多允许上传 3 个文件
    allowedFileTypes: ['image/*', 'video/*'] // 允许的文件类型
  }
});

uppy.use(XHRUpload, {
  endpoint: '/api/upload',
  fieldName: 'file', // 后端接受文件的字段名称
  formData: true, // 使用 FormData 传输
  headers: {
    authorization: 'Bearer token' // 设置自定义请求头
  }
});

uppy.on('upload-success', (file, response) => {
  console.log('上传成功:', response);
});

uppy.on('upload-error', (file, error) => {
  console.error('上传失败:', error);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

优点:

  • 简化了复杂的分片上传、断点续传等功能的实现。
  • 提供了丰富的插件和配置选项,适合不同场景需求。
  • 内置 UI 和进度控制,开发者无需额外编写代码。

缺点:

  • 需要引入第三方库,增加了项目的依赖。
  • 部分库配置较为复杂,学习成本较高。

适用场景:

  • 大文件上传、断点续传、上传失败重试等复杂需求。
  • 需要定制化的文件上传流程和用户界面。

# 二、方式对比总结

方式 优点 缺点 适用场景
传统表单上传 实现简单,兼容性好 页面刷新,用户体验差 简单的表单文件上传,安全性要求不高
原生 XMLHttpRequest 控制精细,支持异步上传 代码复杂,需要手动处理进度、错误 控制权要求高的场景,如学习底层原理
Axios 异步上传 封装好,代码简洁,错误处理友好 增加了库依赖,对比原生灵活性稍差 大部分文件上传场景,需进度监控
多文件上传 支持批量上传,简化操作 需要管理多个文件的进度和错误 批量上传,如图片、文档批量导入
大文件分片上传 支持断点续传,提高稳定性 实现复杂,前后端配合要求高 超大文件上传,网络不稳定的场景
第三方库(如 Uppy) 功能全面,简化复杂场景 引入库依赖,配置复杂 大文件上传、高度定制化需求的场景

# 三、重要 API 和参数详解

  1. enctype="multipart/form-data"

    • 必须设置在表单上,以确保文件上传数据的正确格式。
  2. FormData 对象

    • 用于封装文件和其他表单数据,支持复杂的数据结构传输,是上传文件的关键对象。
  3. xhr.upload.onprogress 和 axios.onUploadProgress

    • 用于实时监控上传进度,提供上传百分比等信息。
  4. file.slice()

    • 用于将大文件按指定大小切片,是分片上传的核心方法。
  5. 第三方库的配置项(如 Uppy 的 restrictions 和 endpoint)

    • 用于控制上传文件的大小、数量和类型,适合定制化场景。

总结

  • 传统表单上传 适合最基础的场景,但现代项目更推荐使用异步上传。
  • 原生 XMLHttpRequest 适合学习底层实现,或者需要更高控制权的项目。
  • Axios 是实际开发中推荐使用的文件上传方式,它封装了底层的复杂性,提供了更友好的 API 和错误处理。
  • 第三方库(如 Uppy) 则在复杂的大文件上传场景中提供了更高的扩展性和定制化支持。
编辑此页 (opens new window)
上次更新: 2025/03/16, 22:19:39
按钮组件
前端文件下载

← 按钮组件 前端文件下载→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式