form 的 method 属性必须设为 POST;GET 会明文暴露参数,仅适用于无副作用的查询操作;enctype 必须匹配场景,否则后端无法解析;submit 事件中需 preventDefault() 拦截校验;CSRF token 必须正确嵌入 form 内并同步更新。

form 的 method 属性该设成 POST 还是 GET?
绝大多数需要提交用户输入的表单,method 必须设为 POST。不是“建议”,是安全底线——GET 会把所有参数拼在 URL 里,浏览器地址栏、服务器日志、代理缓存、Referer 头里全暴露明文数据。
常见错误现象:GET 提交登录表单,密码出现在 Nginx 日志或 Chrome 地址栏;用 GET 传敏感筛选条件(如 ?user_id=123&token=abc),被转发链接直接泄露。
-
GET只适用于无副作用、纯查询类操作(如搜索关键词、分页跳转) -
POST是默认且安全的选择,配合CSRFtoken 才算完整防护 - 别信“我只传几个字段,不重要”——攻击者不需要理解字段含义,只要能重放或篡改就构成风险
为什么 enctype 不配对会导致 POST 提交失败?
表单用了 method="POST",但没设 enctype 或设错,后端可能收不到 request.body 或解析为空。根本原因是浏览器按不同编码规则序列化数据,后端框架只认特定格式。
使用场景:上传文件必须用 enctype="multipart/form-data";普通文本输入默认用 application/x-www-form-urlencoded(也是省略 enctype 时的浏览器默认值);text/plain 几乎不用,仅调试可见原始换行。
立即学习“前端免费学习笔记(深入)”;
- 没上传文件却写了
enctype="multipart/form-data":后端可能解析出空字段(如 Express 的body-parser默认不处理 multipart) - 上传文件却漏写
enctype:文件控件的值不会进请求体,req.files或request.FILES为空 - Django/Flask/Express 等框架对
enctype类型有强依赖,不匹配就等于“发了,但对方没收到”
submit 按钮点击后还能不能拦截并校验?
能,但必须在 submit 事件里 event.preventDefault(),否则表单立刻发出,JS 校验形同虚设。很多人误以为 onclick 在按钮上就够了,其实点击后默认行为已触发。
常见错误现象:前端校验弹窗提示“邮箱格式错误”,但页面仍跳转或刷新;校验通过后重复提交(比如用户狂点按钮)。
- 监听
form元素的submit事件,不是按钮的click - 校验失败时必须调用
event.preventDefault(),否则阻止无效 - 提交成功后建议禁用按钮(
button.disabled = true),防重复提交——后端幂等只是补救,前端拦截更直接
CSRF token 不加或加错位置,为什么后端总报 403?
CSRF token 不是可选插件,而是表单提交的必要凭证。它必须作为隐藏字段放在 form 内部,且名字要和后端约定一致(如 Django 的 csrfmiddlewaretoken,Laravel 的 _token)。
容易踩的坑:token 放在 form 外、用 JS 动态插入但时机不对(比如 DOM 尚未加载完)、前后端 name 不一致、token 值为空或过期。
- token 必须随每次页面渲染生成新值,不能硬编码或复用旧值
- 如果用 AJAX 提交,需从 meta 标签或 cookie 中取 token,并手动加到请求头(
X-CSRF-TOKEN)或数据体中 - Vue/React 单页应用里,容易忽略服务端渲染时 token 的注入时机,导致首屏表单失效
最常被忽略的一点:token 是防跨站伪造,不是防 XSS。XSS 漏洞存在时,攻击者照样能读取并提交 token——所以 CSP、输入过滤、输出转义一个都不能少。











