RFC 10008: HTTP QUERY 方法
RFC 10008 定义了 HTTP 的 QUERY 方法,为执行需要请求体的安全且幂等的请求提供了一种标准化的方式。该方法弥补了 GET(安全且幂等,但通常受限于 URI 长度)与 POST(支持请求体,但默认既不安全也不幂等)之间的差距。
问题所在:URI 长度与方法语义
传统上,HTTP 客户端使用 GET 进行查询,通过 URI 查询字符串传递参数。然而,当查询数据量过大导致 URI 无法承载时,开发者通常会诉诸于使用 POST。虽然 POST 支持请求体,但它缺乏自动重试和中间件高效缓存所需的安全与幂等语义。
RFC 10008 通过引入 QUERY 来解决这个问题,它允许将查询操作的输入作为请求内容传递,同时明确保持安全与幂等的特性。
QUERY 方法的核心属性
QUERY 方法旨在作为复杂查询时 GET 的直接替代方案。其主要特征包括:
- 安全且幂等:与
GET一样,QUERY请求不会改变目标资源的状态,并且可以多次重复执行而不会产生副作用。这使得基础设施可以在连接失败后进行自动重试。 - 请求体:与
GET不同,QUERY期望接收一个请求体(查询内容)以及相应的Content-Type头部。如果Content-Type缺失或与内容不一致,服务器必须使请求失败。 - 可缓存:
QUERY请求的响应是可缓存的。缓存键(cache key)必须包含请求内容及相关的元数据。为了提高效率,缓存可能会对请求内容进行规范化处理,以消除语义上无关紧要的差异。
HTTP 方法对比
| 属性 | GET | QUERY | POST |
|---|---|---|---|
| 安全 | 是 | 是 | 可能不是 |
| 幂等 | 是 | 是 | 可能不是 |
| 请求体 | 无定义的语义 | 期望接收 | 期望接收 |
| 可缓存 | 是 | 是 | 是(有限) |
资源识别与重定向
为了维持“重要资源应通过 URI 识别”的原则,RFC 10008 描述了服务器如何将 QUERY 请求映射到 URI:
- 等效资源:服务器可以为“等效资源”分配一个 URI——即代表特定
QUERY请求及其目标的资源。如果分配了该 URI,可以通过Location响应头部提供,从而允许客户端在后续请求中使用GET。 - Content-Location:成功的响应可能包含一个
Content-Location头部,用于标识持有操作结果的资源,该资源可以通过GET获取。 - 重定向:
QUERY支持标准的 HTTP 重定向(301, 302, 307, 308)。303 (See Other) 响应特别指出,可以通过对Location头部中的 URI 发起GET请求来完成原始查询。
发现与实现
服务器可以使用以下机制来发出支持 QUERY 方法及其接受的格式信号:
- OPTIONS 方法:客户端可以使用
OPTIONS来发现Allow头部中是否列出了QUERY。 - Accept-Query 头部:一个新的结构化字段
Accept-Query允许资源列出其支持的特定查询格式媒体类型(例如application/sql,application/jsonpath+json)。
安全与性能考量
安全性
当查询参数包含敏感信息时,QUERY 比 GET 更受青睐,因为 URI 比请求体更容易被中间件记录日志。然而,为结果创建临时 URI 的服务器(通过 Location 或 Content-Location)应确保这些 URI 不会泄露原始请求中的敏感数据。
CORS
由于 QUERY 不在 CORS 安全列表方法中,来自浏览器端代理的请求将需要进行 CORS 预检请求。
社区观点
开发者之间关于 RFC 10008 的讨论显示出意见分歧,一部分人看重语义清晰度,另一部分人则担心采用率和技术开销:
"我喜欢这可以很容易地扩展到让 JS EventSource 在流式 AI 查询上工作……出于某种固执的原因,EventSource 只能使用 GET。"
"如果包含一个强有力的动机示例可能会有助于推广它……将请求体作为缓存键的一部分感觉非常奇怪。"
""I'm seeing the advantages of using this, but I can't help feel like momentum is going to be strongly against adoption."