使用 fetch 上传 formdata 是最简洁兼容的文件与表单混合上传方式,关键在于正确构造 formdata 并让浏览器自动设置带 boundary 的 content-type,不可手动指定。

直接用 fetch 发送 FormData 是目前最简洁、兼容性好、且无需额外库的文件+表单混合上传方式。关键在于正确构造 FormData,不手动设置 Content-Type,让浏览器自动添加带 boundary 的 multipart 请求头。
✅ 正确构造 FormData:文件与字段混传
FormData 天然支持同时追加文件(File 或 Blob)和普通字符串字段,顺序无关,后端按字段名接收即可:
- 用
append('fieldName', fileInput.files[0])添加单个文件 - 用
append('fieldName', 'value')添加文本字段(如用户名、描述、ID 等) - 同名字段可多次
append,后端会收到数组(如多图上传:append('images', file1)、append('images', file2))
✅ fetch 调用要点:别设 Content-Type
这是最容易出错的地方——千万不能手动设置 headers: { 'Content-Type': 'multipart/form-data' }。因为 multipart 请求需要动态生成 boundary,浏览器会在你传入 FormData 实例时自动设置正确的 Content-Type(含 boundary),并组织二进制载荷。
正确写法只需:
fetch('/api/upload', {
method: 'POST',
body: formData // 直接传 FormData 实例
// 不要加 headers!
})
✅ 后端接收建议(以常见框架为例)
服务端需解析 multipart 请求体,不是 JSON:
- Node.js(Express):用
multer中间件(multer().fields([...])或multer().any()) - Python(FastAPI):用
UploadFile和Form依赖注入,字段自动解包 - PHP:
$_FILES获取文件,$_POST获取文本字段 - Java(Spring Boot):用
@RequestParam MultipartFile file+@RequestParam String title
✅ 小技巧:上传进度与错误处理
fetch 本身不提供上传进度,但可通过 XMLHttpRequest 替代;若坚持用 fetch,可配合 AbortController 实现取消,用 try/catch 捕获网络或 4xx/5xx 错误:
- 检查响应状态:
if (!res.ok) throw new Error(res.statusText) - 解析 JSON 响应前先确认
res.headers.get('content-type')?.includes('json') - 超时控制:用
AbortController配合signal选项










