fetch + formdata 异步上传需正确取值(用new formdata(form))、禁设content-type(浏览器自动注入boundary)、纯文本才转json并设application/json,大文件进度需改用xmlhttprequest。

fetch + FormData 是当前最直接、最可靠的异步文件上传方式,不需要额外库,原生支持多文件、文本字段混传,且自动处理 multipart/form-data 的 boundary。
为什么不能只用 event.preventDefault() 就完事?
很多人以为阻止表单默认行为后,直接发个 fetch 就行了,结果后端收不到字段或报 400。根本原因是:没真正取到数据,或者取法错误。
-
new FormData(formElement)是唯一推荐的取值方式——它自动忽略disabled字段、跳过空的type="file",且能正确处理同名多文件(如<input type="file" multiple>) - 千万别用
formElement.querySelectorAll("input")手动拼对象,会漏掉select、textarea、checkbox的 checked 状态逻辑 - 如果后端要 JSON,必须先
Object.fromEntries(new FormData(form))再JSON.stringify(),但含文件时这条路走不通——File对象无法被 JSON 序列化
fetch 提交含文件的表单时,Content-Type 怎么设?
答案是:一个字都不要设。浏览器看到 body 是 FormData 实例,会自动设置 Content-Type: multipart/form-data; boundary=----XXX,并注入正确的分隔符。
- 手动加
headers: { "Content-Type": "multipart/form-data" }→ 导致 boundary 缺失,后端解析失败(常见于 Express + multer 报Unexpected end of form) - 加
"application/json"→ 文件变成[object File]字符串发过去,后端根本拿不到二进制流 - 仅当纯文本字段(无文件)且后端明确要求 JSON 时,才设
Content-Type: application/json,并确保 body 是字符串
上传大文件时怎么知道进度?fetch 支持吗?
fetch 原生不提供上传进度事件。想显示进度条,只有两个现实选择:
- 改用
XMLHttpRequest:监听xhr.upload.onprogress,兼容 IE10+,API 稍啰嗦但可控性强 - 保持
fetch,但接受“无进度”——适合中小文件( - 别信“用
ReadableStream+AbortController模拟进度”的方案,它只能读取响应体流,对请求体上传无效
表单验证和异步提交能共存吗?
能,而且应该共存。HTML5 原生验证(required、pattern、type="email")不是摆设,form.reportValidity() 和 form.requestSubmit() 就是为这设计的。
-
form.reportValidity():只校验、不触发 submit 事件,适合在按钮点击时提前检查 -
form.requestSubmit():触发完整校验流程(聚焦错误字段 + 显示 tooltip),校验通过后才派发submit事件——这时再preventDefault()并fetch,语义和体验都最自然 - 注意:Android WebView 旧版本不支持
requestSubmit(),降级写法是reportValidity() && !hasInvalidField手动判断
name 属性必须和后端约定一致**。前端 formData.append("avatar", file),后端却按 req.files.profile_pic 去取,必然为空——这种错不会报 JS 异常,只会静默失败。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











