编程 前端文件上传全攻略:从表单提交到分片上传

2025-08-16 09:29:45 +0800 CST views 27

《前端文件上传全攻略:从表单提交到分片上传》

在现代 Web 开发中,文件上传几乎是必备技能。无论是简单的头像上传,还是复杂的网盘系统,前端都需要灵活应对不同场景。本文将详细介绍四种常见上传方案,并提供可运行 Demo。


方案一:经典表单提交

这是最原始的文件上传方式,不依赖 JavaScript。通过 HTML 表单直接提交到服务器。

<form action="/upload" method="post" enctype="multipart/form-data">
  <input type="file" name="myFile">
  <button type="submit">上传</button>
</form>

要点

  • method="POST":HTTP POST 方法。
  • enctype="multipart/form-data":必须设置为 multipart/form-data,否则文件无法上传。

优点:实现简单,兼容性好。
缺点:上传会刷新页面,不符合现代 Web 的无刷新体验。


方案二:现代标准 — Ajax 异步上传

使用 FormData + fetch 可以实现无刷新上传,体验流畅。

const fileInput = document.getElementById('file-input');
const uploadButton = document.getElementById('upload-btn');

uploadButton.addEventListener('click', async () => {
  if (!fileInput.files.length) return;

  const formData = new FormData();
  formData.append('file', fileInput.files[0]);

  try {
    const response = await fetch('/upload', {
      method: 'POST',
      body: formData
    });
    const result = await response.json();
    alert('上传成功: ' + result.message);
  } catch (err) {
    console.error(err);
    alert('上传失败,请重试');
  }
});

优点

  • 页面无刷新。
  • 可结合进度条、错误处理等功能。
  • 功能灵活,现代 Web 应用首选。

方案三:Base64 编码上传

将文件读取为 Base64 字符串,并通过 JSON 发送。

const file = fileInput.files[0];
const reader = new FileReader();
reader.readAsDataURL(file);

reader.onload = async () => {
  const base64Data = reader.result;
  await fetch('/upload', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ file: base64Data })
  });
};

特点

  • 文件嵌入 JSON,可统一处理。
  • 体积增加约 33%,适合小文件或特定需求。

方案四:大文件杀手 — 分片上传

针对 GB 级大文件,一次性上传风险高,分片上传是最佳方案。

核心思路

  1. 使用 File.prototype.slice() 将大文件切成小块(Chunk)。
  2. 每个分片生成唯一标识(如 Hash),单独上传。
  3. 全部上传完成后,通知服务器合并成完整文件。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>分片上传 Demo</title>
<style>
  body { font-family: Arial; padding: 20px; }
  input, button { margin-top: 10px; display: block; }
  .progress { margin-top: 5px; width: 300px; height: 20px; background: #eee; }
  .progress-bar { height: 100%; width: 0; background: #4caf50; }
</style>
</head>
<body>

<h2>大文件分片上传 Demo</h2>
<input type="file" id="file-input">
<button id="upload-btn">开始上传</button>
<div class="progress">
  <div class="progress-bar" id="progress-bar"></div>
</div>
<div id="status"></div>

<script>
const fileInput = document.getElementById('file-input');
const uploadButton = document.getElementById('upload-btn');
const progressBar = document.getElementById('progress-bar');
const status = document.getElementById('status');

const CHUNK_SIZE = 1024 * 1024; // 1MB 分片
let fileId = null;

async function uploadChunk(file, chunk, index, totalChunks) {
  const formData = new FormData();
  formData.append('fileId', fileId);
  formData.append('chunkIndex', index);
  formData.append('totalChunks', totalChunks);
  formData.append('chunk', chunk);

  await fetch('/upload-chunk', { method: 'POST', body: formData });
  progressBar.style.width = ((index + 1) / totalChunks * 100) + '%';
}

async function uploadFile(file) {
  fileId = file.name + '-' + Date.now(); // 文件唯一标识
  const totalChunks = Math.ceil(file.size / CHUNK_SIZE);

  for (let i = 0; i < totalChunks; i++) {
    const start = i * CHUNK_SIZE;
    const end = Math.min(file.size, start + CHUNK_SIZE);
    const chunk = file.slice(start, end);
    await uploadChunk(file, chunk, i, totalChunks);
  }

  // 通知服务器合并文件
  await fetch('/merge-chunks', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ fileId, fileName: file.name })
  });

  status.textContent = '上传完成!';
}

uploadButton.addEventListener('click', () => {
  if (!fileInput.files.length) {
    alert('请选择文件');
    return;
  }
  status.textContent = '';
  progressBar.style.width = '0';
  uploadFile(fileInput.files[0]);
});
</script>

</body>
</html>

优点

  • 支持断点续传。
  • 无惧网络中断。
  • 前后端可灵活处理大文件上传。

缺点:实现复杂,需要前后端配合。


总结

在实际开发中:

  • 小文件:Ajax + FormData 足够使用。
  • 大文件或网盘场景:推荐分片上传。
  • 小文件嵌入 JSON:Base64 可选,但需注意体积。
  • 极简方案:经典表单提交,兼容性好,但体验欠佳。

可运行 Demo

下面是一个支持 Ajax 异步上传的小文件 Demo:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>文件上传 Demo</title>
<style>
  body { font-family: Arial, sans-serif; padding: 20px; }
  input, button { margin-top: 10px; }
</style>
</head>
<body>

<h2>Ajax 异步文件上传 Demo</h2>
<input type="file" id="file-input">
<button id="upload-btn">上传文件</button>
<div id="status"></div>

<script>
const fileInput = document.getElementById('file-input');
const uploadButton = document.getElementById('upload-btn');
const status = document.getElementById('status');

async function uploadFile(file) {
  const formData = new FormData();
  formData.append('file', file);

  status.textContent = '上传中...';
  try {
    const res = await fetch('/upload', { method: 'POST', body: formData });
    const result = await res.json();
    status.textContent = '上传成功: ' + result.message;
  } catch (err) {
    console.error(err);
    status.textContent = '上传失败,请重试';
  }
}

uploadButton.addEventListener('click', () => {
  if (!fileInput.files.length) {
    alert('请选择文件');
    return;
  }
  uploadFile(fileInput.files[0]);
});
</script>

</body>
</html>

Demo 特性:

  1. Ajax 异步上传:无需刷新页面。
  2. 状态提示:显示上传中、成功或失败。
  3. 易于扩展:可加入多文件上传、进度条或分片上传逻辑。
复制全文 生成海报 前端开发 文件上传 Web技术

推荐文章

使用Python实现邮件自动化
2024-11-18 20:18:14 +0800 CST
如何在Vue3中处理全局状态管理?
2024-11-18 19:25:59 +0800 CST
2024年公司官方网站建设费用解析
2024-11-18 20:21:19 +0800 CST
WebSQL数据库:HTML5的非标准伴侣
2024-11-18 22:44:20 +0800 CST
JS中 `sleep` 方法的实现
2024-11-19 08:10:32 +0800 CST
Nginx 如何防止 DDoS 攻击
2024-11-18 21:51:48 +0800 CST
使用Rust进行跨平台GUI开发
2024-11-18 20:51:20 +0800 CST
ElasticSearch 结构
2024-11-18 10:05:24 +0800 CST
赚点点任务系统
2024-11-19 02:17:29 +0800 CST
PostgreSQL日常运维命令总结分享
2024-11-18 06:58:22 +0800 CST
使用 Nginx 获取客户端真实 IP
2024-11-18 14:51:58 +0800 CST
如何在Vue 3中使用Ref访问DOM元素
2024-11-17 04:22:38 +0800 CST
markdown语法
2024-11-18 18:38:43 +0800 CST
跟着 IP 地址,我能找到你家不?
2024-11-18 12:12:54 +0800 CST
25个实用的JavaScript单行代码片段
2024-11-18 04:59:49 +0800 CST
前端代码规范 - Commit 提交规范
2024-11-18 10:18:08 +0800 CST
程序员茄子在线接单