使用 FormData 构造表单数据并用 fetch 发送是现代前端文件上传最简洁可靠的方式:1. 用 new FormData() 初始化,append 添加字段和文件;2. fetch 直接传入 formData 作 body,不设 headers;3. 注意后端返回 JSON 类型及大文件进度监听限制。

直接用 FormData 构造表单数据,再通过 fetch 发送,无需手动序列化、不用设置 Content-Type(浏览器自动设为 multipart/form-data 并附带正确 boundary),是现代前端上传文件最简洁可靠的方式。
1. 创建 FormData 并填充字段和文件
从表单元素创建可选,但推荐显式构造,便于控制字段顺序和动态添加内容:
- 用
new FormData()初始化空对象 - 调用
.append(key, value)添加文本字段或File对象(如input[type="file"].files[0]) - 同名多文件可多次
append(后端按数组接收),或传入FileList(如input.files)
示例:
const formData = new FormData();
formData.append('username', 'alice');
formData.append('avatar', document.getElementById('avatar').files[0]);
formData.append('photos', document.getElementById('photos').files[0]);
formData.append('photos', document.getElementById('photos').files[1]); // 多图上传
2. 使用 fetch 提交,不设 headers
FormData 本身已包含完整 multipart 结构,若手动设置 Content-Type,浏览器将无法自动注入 boundary,导致后端解析失败。只需:
立即学习“前端免费学习笔记(深入)”;
- 指定请求方法为
POST - 将
formData直接作为body传入 - 不配置
headers(尤其避免Content-Type)
示例:
fetch('/upload', {
method: 'POST',
body: formData
})
.then(res => res.json())
.then(data => console.log('上传成功:', data));
3. 处理响应与常见问题
后端返回 JSON 是常规做法,但注意:
- 确保后端实际返回
application/json,否则res.json()会报错 - 上传大文件时可监听
upload.onprogress—— 但需从fetch的AbortController+ReadableStream或改用XMLHttpRequest实现进度,原生fetch不支持上传进度事件 - 如需带认证,可加
credentials: 'include'或headers: { Authorization: 'Bearer xxx' }—— 但后者仅适用于非FormData场景;若必须鉴权且用FormData,应由后端通过 Cookie 或 token 字段校验
4. 完整可运行示例(含错误处理)
HTML 片段:
<form id="uploadForm"> <input type="text" name="title" placeholder="标题" required> <input type="file" name="cover" accept="image/*" required> <button type="submit">上传</button> </form>
JS 逻辑:
document.getElementById('uploadForm').addEventListener('submit', async (e) => {
e.preventDefault();
const form = e.target;
const formData = new FormData(form); // 自动提取所有 input[name] 值
try {
const res = await fetch('/api/upload', { method: 'POST', body: formData });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const result = await res.json();
console.log('结果:', result);
} catch (err) {
console.error('上传失败:', err);
}
});



















