必须阻止表单默认提交行为,否则fetch不执行;一律用formdata封装数据且不设content-type;fetch需检查response.ok判断http错误;csrf token须从dom动态读取并加入formdata。

Fetch 提交表单前必须阻止默认提交行为
直接给 <form></form> 绑定 submit 事件但不调用 event.preventDefault(),浏览器会走传统页面跳转提交,fetch 根本不会执行。这是最常被忽略的第一步。
实操建议:
- 监听
form.addEventListener('submit', handler),在handler开头立刻写event.preventDefault() - 不要用
<button type="submit"></button>触发后靠click事件捕获——它无法可靠阻止表单提交 - 确保事件委托绑定正确:如果表单是动态插入的,用
document.addEventListener('submit', ...)并检查event.target.matches('form')
FormData 是最稳妥的表单数据封装方式
手动拼 URLSearchParams 或 JSON 对象容易出错:文件上传失败、布尔/空值处理异常、编码问题(比如中文变 %E4%BD%A0 却没设 Content-Type)。
实操建议:
- 一律用
new FormData(formElement)构造数据,它自动处理所有字段类型(包括<input type="file">) - 提交时不要设置
headers中的Content-Type—— 浏览器会自动设为multipart/form-data并带上正确 boundary;手动设反而会导致服务端解析失败 - 如需额外字段,用
formData.append('token', 'xxx'),别混用JSON.stringify()
服务端返回 400/500 时 fetch 不会自动抛错
fetch 只在网络失败(断网、DNS 错、CORS 拒绝)时 reject,HTTP 状态码如 400 Bad Request 或 500 Internal Server Error 仍算“成功”,response.ok 才是判断依据。
实操建议:
- 每次
await fetch(...)后加if (!response.ok) throw new Error(`${response.status} ${response.statusText}`) - 后端返回的错误详情(如字段校验失败信息)通常在
response.json()中,需显式 await 解析,不能假设response.text()就是纯文本 - 避免只靠
catch捕获网络错误而漏掉业务错误,二者要分开处理
CSRF token 必须从 DOM 中读取,不能硬编码
多数现代后端(Django、Rails、Spring Security)要求表单提交携带 CSRF token,它通常由服务端渲染进隐藏字段:<input type="hidden" name="csrf_token" value="abc123">。硬编码 token 会导致多用户冲突或过期失效。
实操建议:
- 从表单内查找:
const tokenInput = form.querySelector('input[name="csrf_token"]'); const token = tokenInput?.value; - 把 token 加入
FormData:formData.append('csrf_token', token),而不是塞进headers - 如果后端用
X-CSRF-Token请求头(如 Rails API 模式),才需要单独提取并设置:headers: { 'X-CSRF-Token': token }
FormData 的边界行为、fetch 对 HTTP 状态码的沉默处理、CSRF token 的动态性,这三处最容易在联调时卡住半天。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











