action属性不填或为空时,表单数据提交到当前页面完整URL(含query string和hash);formaction属性可覆盖action,仅对type="submit"的按钮生效,优先级最高。

action 属性不填或填空字符串,数据到底发到哪了
浏览器会把表单数据提交到当前页面的完整 URL(含 query string 和 hash),比如你在 https://example.com/login?from=mobile#step2 页面点提交,请求就会发往这个地址。后端通常没配这个路由,结果不是 404 就是原样返回、页面刷新——看着像没反应,其实是发出去了,只是没人接。
常见误操作:
- 写
action="."或action="./":部分浏览器解析成https://site.com/./,路径错误 - 省略
action又没配后端处理当前页的 POST 路由:必然失败 - 在前端路由(如 Vue Router 的 history 模式)下留空 action:请求能发出,但响应可能被 JS 拦截或触发意外跳转
相对路径、绝对路径、完整 URL 怎么选
关键看部署结构和跨域需求,不是“哪个更高级”,而是“哪个匹配你的服务器配置”。
相对路径(推荐用于同站接口):action="api/login" 或 action="./api/login"。前者基于当前 HTML 所在目录解析;后者显式声明“当前目录”,更稳妥,尤其当页面嵌套较深时。
立即学习“前端免费学习笔记(深入)”;
绝对路径(适合根目录统一 API):action="/api/login"。注意它从域名根开始,和当前 HTML 文件位置无关。Nginx 配置里常有 location /api/ { proxy_pass http://backend; },这时必须用这种写法。
完整 URL(仅限跨域且后端已配 CORS):action="https://api.example.com/v1/submit"。别为了“看起来完整”就乱加协议域名——表单提交不走 fetch,CORS 错误不会报在控制台,只会静默失败或跳转到空白页。
formaction 覆盖 action 的真实行为
formaction 是 <input type="submit"> 或 <button type="submit"> 的属性,优先级高于 <form> 的 action。它不是“可选功能”,而是明确支持多提交目标的原生机制。
典型用例:
- 一个表单两个按钮:“保存草稿”走
formaction="/draft",“正式提交”走formaction="/submit" - 管理后台中,“导出 CSV”和“删除选中”共用一个表单结构,但目标 URL 完全不同
注意:formaction 在 IE9 及更早版本不支持;如果 JS 动态设置,需确保在点击前完成赋值,否则仍按 <form> 的 action 提交。
JS 拦截提交时 action 还有没有用
完全没用——只要你调了 event.preventDefault(),action 和 method 就彻底失效。后续请求由 fetch、axios 或 XMLHttpRequest 控制。
但容易踩的坑是:只写了发送逻辑,忘了拦默认行为。结果就是一次请求由 JS 发出,另一次由浏览器原生提交,后端收到重复数据,前端还可能跳转或刷新。
正确做法:
- 监听
submit事件 - 第一行必须是
event.preventDefault() - 再调用
fetch("/api/submit", { method: "POST", body: formData })
复杂点在于:表单提交是原子导航行为,一旦触发,无法中途“撤回”。所以 action 的值是否可信、是否已被污染,必须在用户点击前就确认好——而不是寄希望于 JS 临场修正。



















