用 formdata 配合 fetch 实现多文件无刷新上传,需遍历 input.files 将每个文件以相同字段名(如“files”)append 到 formdata;fetch 会自动设置 multipart/form-data 及 boundary;进度监听推荐 xmlhttprequest 或 axios;后端需用 multer 等中间件解析 multipart 数据。

用 FormData 配合 Fetch 实现多文件无刷新上传,核心是把 <input type="file" multiple> 选中的文件构造成 FormData 对象,再通过 Fetch 发送到后端,同时处理好进度、错误和响应解析。
构造 FormData 并添加多个文件
用户选择多个文件后,input.files 是一个 FileList 对象。不能直接传入 FormData,但可以遍历它,逐个 append 到 FormData 中。注意:每个文件要使用相同的字段名(如 "files"),后端才能识别为数组或多个文件。
示例代码:
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async () => {
const formData = new FormData();
for (let file of input.files) {
formData.append('files', file); // 字段名统一,后端接收为多文件
}
try {
const res = await fetch('/upload', {
method: 'POST',
body: formData,
// ⚠️ 不要手动设置 Content-Type!浏览器会自动设为 multipart/form-data 并带上 boundary
});
const data = await res.json();
console.log('上传成功', data);
} catch (err) {
console.error('上传失败', err);
}
});
监听上传进度(需后端支持流式响应)
Fetch 原生不提供上传进度事件,但可通过 XMLHttpRequest 或第三方库(如 axios)实现。如果坚持用 Fetch,可借助 ReadableStream + ProgressEvent 模拟,但兼容性和实用性有限。更推荐方案:
- 使用
XMLHttpRequest.upload.onprogress(简单可靠,兼容性好) - 或改用
axios:axios.post(url, formData, { onUploadProgress: e => {...} }) - 若必须用 Fetch,可配合
fetch + AbortController做取消,但进度仍需服务端返回中间状态(如轮询上传ID)
后端接收要点(以 Express 为例)
前端发的是 multipart/form-data,后端需解析该格式。Express 默认不处理,需中间件:
-
multer(最常用):配置array('files')接收多个同名文件 -
busboy或formidable:轻量替代方案 - 确保路由能接收 POST,并正确解析字段名(如
req.files或req.files.files)
示例(Multer):
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
app.post('/upload', upload.array('files'), (req, res) => {
console.log(req.files); // 数组,每个元素含 originalName、path 等
res.json({ success: true, count: req.files.length });
});
增强体验:禁用按钮、显示文件名、错误提示
真实场景中需避免重复提交、给用户明确反馈:
- 上传开始前禁用提交按钮,完成后恢复
- 显示已选文件名列表(
Array.from(input.files).map(f => f.name)) - 捕获常见错误:网络失败、4xx/5xx 响应、空文件、文件过大(可在前端用
file.size校验) - 上传成功后清空
input.value,否则再次选择相同文件不会触发change事件










