我倾向于不使用内容协商的原因
Web 开发者正在权衡 HTTP 内容协商的利与弊,尤其是在用同一个 URL 同时为人类提供 HTML、为机器提供 JSON 时。许多人主张将“超媒体”HTML 端点与 JSON 数据 API 分开,以避免把展示相关的问题混入公共接口、简化缓存/CDN 行为,并让 URL 更可预测,即便这意味着放弃 HTTP 某些更抽象的特性。另一些人指出,虽然诸如 `Accept` 和 `Vary` 这样的头部在理论上可以优雅地处理格式和版本控制,但现实中的工具、CDN 和团队实践往往让更简单的基于 URL 或查询参数的方法更实用。
内容协商:有用性与缺点
- 有些人认为,在有限场景下内容协商是必要的:例如在 JSON/XML 之间选择、二进制与 JSON 之间选择,或在多种数据格式(CSV/TSV/Parquet)之间选择;在语义网/链接数据用例中,同一个标识符应当对浏览器提供 HTML、对库提供 JSON-LD/RDF。
- 也有人认为这属于过度设计:数据领域 JSON 占主导,内容领域 HTML 占主导,因此“协商”只会增加复杂度而收益有限。许多客户端并不真正理解
Accept头,现实中的用户往往更喜欢简单的查询参数。 - 还有几个人觉得同一个 URL 和方法却能返回截然不同的格式,在概念上令人困惑。
URLs、查询参数与头部
- 许多人更喜欢显式 URL 或查询参数(
/item.json、?format=json),因为它们更有人类可读性、在日志中更可见、方便配合 curl,而且更利于缓存。 - 支持使用头部的人强调,
Accept是标准化的,允许加权偏好和自定义媒体类型(包括版本控制),并且避免了那种“字符串化类型”的 URL 变通做法。 - 关于 API 版本控制的争论仍在继续:像
/v1/这样的路径段被视为更常见、更显眼;也有人更喜欢通过Accept使用版本化媒体类型。
CDN、缓存,以及 Vary/Accept
- 多条评论指出,Cloudflare 和其他 CDN 往往会忽略
Vary(尤其是非图片内容),这会破坏内容协商,并导致返回错误的缓存变体。 - 一些 CDN 运营者出于性能、缓存占用和元数据分发等原因,会限制
Vary。这会把实践者从协商推向不同端点的做法。
超媒体 vs 数据 API;htmx vs SPA
- 许多人赞同将“面向人类的超媒体/HTML 端点”和“面向机器的数据/JSON API”分开,以避免把分页、排序和 UI 特有的考虑混入公共 API。
- htmx/服务器渲染流程受到称赞,因为它们让团队只需构建一次应用,避免在 JS SPA 中重复逻辑,并且只用很少的 JavaScript 就能加入丰富交互。
- 怀疑者则认为,现代客户端框架(例如 React+TypeScript)为复杂 UI 提供了更好的模式、类型检查和代码局部性,而把超媒体模式用于复杂的有状态应用则显得别扭。
什么算 API?
- 对术语存在分歧:有人认为紧耦合的 HTML“超媒体 API”并不是真正面向多个独立客户端的 API,只是应用的一部分;也有人坚持 HTML 本身就是浏览器可用的网络 API。