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)。

安全与性能考量

安全性

当查询参数包含敏感信息时,QUERYGET 更受青睐,因为 URI 比请求体更容易被中间件记录日志。然而,为结果创建临时 URI 的服务器(通过 LocationContent-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."

Sources