滑坡

发布: (2026年2月17日 GMT+8 05:00)
5 分钟阅读
原文: Dev.to

Source: Dev.to

Source:

介绍

最近在 LinkedIn 上的一篇帖子讨论了使用查询参数来请求资源的替代表示。其思路是仅投影所需的字段,例如:

GET /users/1

响应

HTTP/1.1 200 OK
Content-Type: application/json

{"username": "Name", "displayName": "Display Name"}

如果客户端只需要 displayName,请求可以写成:

GET /users/1?fields=displayName

响应

HTTP/1.1 200 OK
Content-Type: application/json

{"displayName": "Display Name"}

乍一看这似乎是合理的,但它引发了关于查询组件正确使用方式的疑问。

RFC 3986 概述

RFC 3986 定义了 URI 的通用语法:

scheme ":" hier-part [ "?" query ] [ "#" fragment ]
  • Scheme – 协议标识符(例如 httpftp)。不区分大小写。
  • Authority – 主机、可选端口和可选用户信息(例如 //www.example.com:80)。
  • Path – 用于标识资源的层级段序列。
  • Query – 非层级数据,通常是 key=value 键值对,由 ? 引入。
  • Fragment – 次级资源标识符(例如页面锚点),由 # 引入;由用户代理处理,而非服务器。

规范将查询字符串视为一组不透明的键‑值对。它为诸如 fieldssortfilter 等参数规定任何语义。

查询参数作为迷你 DSL

使用查询参数作为指令(例如 fieldssortfilter)实际上在有限的 HTTP 动词之上创建了一种领域特定语言(DSL)。示例:

GET /users/1?fields=displayName
GET /users/?sort=
GET /users/?filter=
GET /users?id=1&fields=displayName

这里 id 是搜索参数,而 fields 是投影指令。随着时间推移,这类约定可能会成为事实标准,迫使 API 设计者维护额外的文档并将这些关键字视为保留字。

为什么这会成为问题

  • URI 的不透明性 – RFC 3986 将 ? 之后的所有内容视为不透明;将其解释为 DSL 会引入隐藏的契约。
  • 动词与指令的耦合 – 有限的 HTTP 方法集合被额外语义所负载。
  • 维护负担 – 每新增一个指令(例如 fieldssort)都需要文档说明并让客户端知晓。

内容协商作为替代方案

投影本质上是一个表示(representation)的问题。HTTP 已经提供了一种机制,让客户端请求特定的表示形式:内容协商

GET /users/1
Accept: application/json; fields=displayName

Accept 头部可以携带媒体类型参数,例如:

GET /users/1
Accept: application/json; q=0.9; charset=UTF-8

这些参数是开放式的,服务器可以根据需要进行解释。

RFC 6906 – Profile 参数

RFC 6906 引入了一种更结构化的方式来请求表示的变体:

GET /users/1
Accept: application/json; profile="http://www.example.com/profiles/user-summary"

或者,也可以定义自定义媒体类型:

GET /users/1
Accept: application/vnd.user.displayname+json

实际考虑

  • 链接 – 在创建资源时,使用已经包含所需投影的 URL 更为简单:

    Location: /users/1?fields=displayName

    使用额外的头部来传达投影指令会使响应变得复杂。

  • 缓存 – 缓存本身并不了解自定义查询参数的语义。正确的缓存需要显式的 Vary: 头部,不同实现的行为可能会有所差异,导致缓存未命中或数据陈旧。

结论

查询参数快捷方式的普遍使用并不自动使其成为架构最佳实践。虽然它们很实用,但会引入隐藏的契约,可能削弱 REST 所追求的清晰性和互操作性。请记住:

“架构的衰退不是因为错误的决定,而是因为被遗忘的理由。”

明确地将此类快捷方式记录为 约定 而非标准,有助于保留其初衷,并防止偏离既定 HTTP 语义的滑坡。

0 浏览
Back to Blog

相关文章

阅读更多 »

开发者对幂等性的误解

快速提问:一个在后续调用中返回 404 的 DELETE endpoint 是否是幂等的?如果你因为响应变化而说不是,那么这篇 article 适合你。Idem…