HTTP QUERY 方法:通过 RFC 10008 解决复杂的 API 查询
HTTP QUERY 方法:通过 RFC 10008 解决复杂的 API 查询
RFC 10008 定义了新的 HTTP QUERY 方法,为需要请求体的复杂只读操作提供了一种标准化的方式。这解决了 GET 查询参数的局限性与使用 POST 进行数据检索在语义上的不正确性之间长期存在的矛盾。
为什么 HTTP QUERY 方法是必要的
HTTP QUERY 方法是必需的,因为现有方法无法在不损害技术稳定性或 API 语义的情况下,高效地处理复杂的关联查询或深度嵌套的数据结构。
GET 的局限性
虽然 GET 是检索数据的标准方法,但它依赖于 URL 中的查询参数。这种方法在以下几种场景中会失效:
- URL 长度限制: 复杂的过滤器可能会创建巨大的 URL,从而超过浏览器或服务器的字符限制。
- 编码开销: 非 ASCII 或特殊字符必须进行编码,从而增加了请求的大小。
- 安全与日志: 请求参数通常会被服务器和中间件记录在日志中,这可能会暴露敏感数据。
- 缺乏结构: 在 URL 中表达数组或深度嵌套结构没有通用标准(例如,
?roles[]=admin与?roles=admin)。
GET 携带请求体的失败案例
虽然没有 RFC 明确禁止 GET 请求携带请求体,但强烈不建议这样做。在实践中,许多客户端、代理和 Web 服务器对 GET 请求体的处理并不一致——有些直接拒绝,而有些则完全丢弃请求体。这使得在生产环境中,使用带有请求体的 GET 是一种不可靠的选择。
POST 的语义问题
开发者经常使用 POST 作为一种变通方法,通过发送请求体来进行查询。然而,POST 被定义为非幂等的,且旨在用于资源创建或处理。这会产生以下几个问题:
- 重试: 由于 POST 不是幂等的,在失败时进行自动重试是具有风险的。
- 缓存: 代理和中间件无法自动将 POST 请求识别为只读,从而阻碍了标准缓存机制的使用。
QUERY 方法的技术规范
QUERY 方法旨在在功能上与 GET 相似,但明确支持请求体。其主要特征包括:
- 安全性与幂等性: 与 GET 一样,QUERY 被定义为安全且幂等的,这意味着它不会改变服务器的状态。
- 可缓存性: QUERY 请求可以被缓存。但是,实现时必须将请求体纳入缓存键(cache key)中,以确保针对不同的查询参数返回正确的数据。
实现考虑因素与注意事项
尽管进行了标准化,但 QUERY 方法并不能直接替换所有的搜索端点。开发者应当考虑以下约束:
- 生态系统支持有限: 目前对 QUERY 的支持还很有限。许多代理、防火墙和 Web 服务器可能仍会拒绝该方法。例如,虽然 Kreya API 客户端在 1.20 版本中增加了支持,但广泛采用可能需要数年时间。
- 可链接性: QUERY 请求无法通过简单的 URL 进行书签保存或分享,因为查询参数位于请求体中,而不是 URL 中。
- 缓存复杂度: 为 QUERY 实现自定义缓存比为 GET 实现要复杂,因为缓存键必须从请求体中推导出来。
社区观点与批评
工程师之间的讨论凸显了重视显式标准与倾向于遵循现有惯例之间存在分歧。
支持新方法的论点
有人认为,拥有一个显式的谓词(method)是唯一正确的推进方式,因为使用带有请求体的 GET 是一种“黑客行为”(hack),不应该被标准化。
反对新方法的论点
批评者认为,标准应该遵循“GET 携带请求体”的现有惯例,并争辩说引入一个新的谓词可能会给遗留基础设施带来问题。一位用户指出了“由于历史记录导致的 DoS 风险”,即当仅支持 HTTP/1.1 的昂贵 SSL 拦截代理设备遇到未知的 HTTP 谓词时,可能会发生这种情况。
其他开发者也质疑,仅仅为了支持请求体而添加一个新方法是否是为保持 HTTP 规范的长期相关性而采取的最佳方式,并暗示这可能是一种“阻力最小的路径”,而非一种稳健的设计。