文件上传是 Web 开发的必备技能,从简单的头像上传到复杂的网盘系统,其实现方式多种多样。
姿势一:经典表单提交
这是最原始的方式,无需 JavaScript。通过一个简单的 HTML 表单,利用浏览器的默认行为来完成上传。
核心要点:
- <form> 标签的 method 必须为 POST。
- enctype 属性必须设为 multipart/form-data。
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="myFile">
<button type="submit">上传</button>
</form>
优点在于极致简单,兼容性无敌,但体验不好,上传会导致页面刷新或跳转,不符合现代 Web 应用的要求。
姿势二:现代标准 — Ajax 异步上传
这是目前应用最广泛的方式,它提供了无刷新的流畅体验。核心是 FormData 对象,它可以模拟一个表单,并通过 Ajax 技术(如 fetch)在后台发送。
核心要点:
- 获取用户选择的 File 对象。
- 创建 FormData 实例,并用 .append(key, file) 添加文件。
- 使用 fetch API 发送 FormData。
const fileInput = document.querySelector('input[type="file"]');
async function uploadFile() {
const file = fileInput.files[0];
if (!file) return;
const formData = new FormData();
formData.append('file', file); // 'file' 是与后端约定的字段名
try {
const response = await fetch('/upload', {
method: 'POST',
body: formData, // fetch 会自动设置正确的 Content-Type
});
const result = await response.json();
console.log('上传成功:', result);
} catch (error) {
console.error('上传失败:', error);
}
}
优点在于,无须刷新页面,功能强大(可实现进度条、错误处理)。
姿势三:Base64 编码
这种方式是将文件内容读取为一长串 Base64 编码的字符串,然后作为普通文本(通常是 JSON 的一部分)发送给服务器。
核心思想:
使用 FileReader API 的 readAsDataURL 方法将文件转换为 Base64 字符串。
这个方案的优点在于能将文件嵌入到 JSON 中,后端处理可能更统一,只是编码后体积会增大约 33%,特定需求小文件可用。
姿势四:大文件杀手 — 分片上传
对于 GB 级别的超大文件,一次性上传风险极高,分片上传是终极解决方案。
在前端使用 File.prototype.slice() 将大文件切成多个小块(Chunk),为每个文件生成唯一标识(如 Hash),然后上传这些小块,所有分片上传完毕后,通知服务器将它们按顺序合并成完整文件。
这个方案无惧网络中断,支持断点续传,但需要前后端深度配合。
在实际开发中,Ajax + FormData 是我们的首选方案,根据需要,可增加拖拽/粘贴事件监听优化体验,用分片上传来挑战“BOSS”。