HTTP 请求中的链接与表单
每当用户点击导航链接或提交搜索查询时,浏览器都会发起一个 HTTP 请求。但触发该请求的 HTML 元素是什么——以及如何触发——比大多数开发者意识到的更重要。在 <a> 和 <form> 之间做选择不仅仅是标记偏好,而是一个影响行为、安全性和正确性的语义决策。
核心要点
- 链接(
<a>)用于导航,通常触发 GET 请求。表单(<form>)用于数据提交,同时支持 GET 和 POST。 - 当用户输入影响 URL 时(如搜索查询)使用 GET 表单,当操作改变服务器状态时(如创建账户)使用 POST 表单。
method="link"是无效的 HTML——浏览器会静默回退到 GET,这可能导致意外行为。- HTML 表单原生仅支持 GET 和 POST。对于 PUT、PATCH 或 DELETE,需要使用 JavaScript。
核心区别:HTML 导航 vs 提交
链接(<a>)是导航元素。 它们告诉浏览器:“去获取这个资源。” 点击链接通常会触发一个指向 href 属性中 URL 的 GET 导航请求。就是这样。不收集用户输入,不序列化数据——只是一个纯粹的导航事件。
表单(<form>)是数据提交元素。 它们从用户那里收集输入并将其发送到服务器。表单可以使用 GET 或 POST,具体取决于请求的性质。
以下是快速对比:
| 特性 | <a> 链接 | <form> |
|---|---|---|
| 用途 | 导航 | 数据提交 |
| HTTP 方法 | 仅 GET | GET 或 POST |
| 收集用户输入 | 否 | 是 |
| 右键/在新标签页打开 | 是 | 否 |
| SEO 可抓取 | 是 | 有限 |
| 改变服务器状态 | 否 | 是(使用 POST) |
HTML 表单中的 GET vs POST:各自的应用场景
使用链接进行安全的幂等导航
如果操作不会改变服务器上的任何内容,并且目标可以被收藏或分享,请使用链接:
<a href="/articles/html-basics">阅读 HTML 指南</a>
链接是安全的、幂等的和可缓存的——正是 GET 请求应有的样子。
当用户输入影响 URL 时使用 GET 表单
搜索框是经典示例。用户输入查询,表单将其作为查询字符串附加到 URL:
<form method="get" action="/search">
<input type="search" name="q" placeholder="搜索...">
<button type="submit">搜索</button>
</form>
这会生成 /search?q=your+query——一个可分享、可收藏的 URL。当请求仍然是安全且幂等的,但 URL 参数依赖于用户输入时,使用 GET 表单。
当操作有副作用时使用 POST 表单
创建账户、提交支付或发布评论都会改变服务器状态。这些应该使用 POST 表单:
<form method="post" action="/register">
<input type="email" name="email">
<input type="password" name="password">
<button type="submit">创建账户</button>
</form>
POST 在请求体中发送数据,而不是在 URL 中——这适用于敏感数据和非幂等操作。
Discover how at OpenReplay.com.
常见错误:method="link" 不存在
一些开发者编写 <form method="link"> 希望创建一个”链接按钮”。这是无效的 HTML。浏览器会忽略未知值并回退到默认值——即 GET。表单仍然会提交,但它是静默且错误地进行的。
如果你想要一个导航到某处的按钮,请使用样式化为按钮的链接——而不是表单:
<!-- ❌ 无效 -->
<form method="link" action="/about">
<input type="submit" value="前往关于页面">
</form>
<!-- ✅ 正确 -->
<a href="/about" class="btn">前往关于页面</a>
值得了解的现代表单功能
HTML5 通过 formaction 和 formmethod 属性添加了按钮级别的覆盖,让单个提交按钮可以改变表单提交的位置或方式:
<form method="post" action="/save">
<button type="submit">保存</button>
<button type="submit" formaction="/save-and-publish" formmethod="post">发布</button>
</form>
还值得注意的是:requestSubmit()(与 submit() 不同)在提交前触发表单验证,使其成为 JavaScript 中程序化表单提交的更好选择。
对于 PUT、PATCH 或 DELETE,HTML 表单原生不支持这些方法。你需要使用 JavaScript(fetch、XMLHttpRequest)或服务器端方法覆盖约定。
结论
一旦理解了语义,链接和表单之间的选择就很简单了:
- 导航到页面? 使用链接。
- 收集用户输入进行查询? 使用 GET 表单。
- 提交改变服务器状态的数据? 使用 POST 表单。
- 执行 PUT/PATCH/DELETE? 使用 JavaScript。
选择与操作意图匹配的元素。语义化 HTML 不仅仅关乎正确性——它使你的 UI 可预测、可访问且易于维护。
常见问题
技术上可以,但这通常是错误的语义选择。GET 表单旨在收集用户输入并将其作为查询参数附加到 URL。对于没有用户输入的简单导航,链接是正确的语义选择。链接可被搜索引擎抓取,支持右键上下文菜单,并向浏览器和辅助技术清晰传达导航意图。
浏览器将任何无法识别的 method 值视为无效,并静默回退到 GET,这是默认的表单方法。因此 method 为 link 的表单仍会提交,但其行为与 GET 表单完全相同。这可能掩盖错误并产生令人困惑的行为。始终使用 get 或 post 作为表单的 method 值。
submit() 方法立即发送表单,不运行内置的 HTML 验证,也不触发 submit 事件。requestSubmit() 方法的行为类似于用户点击提交按钮。它首先触发约束验证并触发 submit 事件,允许事件监听器拦截或取消提交。当需要运行验证时使用 requestSubmit()。
HTML 表单仅支持 GET 和 POST 作为 method 值。要发送 DELETE、PUT 或 PATCH 请求,你需要使用 fetch 或 XMLHttpRequest 的 JavaScript。一些服务器端框架还支持方法覆盖模式,你可以提交一个 POST 表单,其中包含一个指定预期 HTTP 方法的隐藏输入字段,然后服务器相应地解释它。
Gain control over your UX
See how users are using your site as if you were sitting next to them, learn and iterate faster with OpenReplay. — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.