新的 HTTP QUERY 方法解释

2026-06-23 1 阅读 CommonGuy
在 RESTful API 的世界中,我们长期以来一直遵循一套严格的(自我强加的)规则。无论您是使用 GET 获取数据、使用 POST 创建实体还是使用 PUT 更新资源,HTTP 方法都会告诉服务器您的意图。最近,RFC 10008 发布,它定义了 HTTP 的新 QUERY 方法。当我们已经有其他 HTTP 方法时,为什么还需要这个?让我们来看看吧。从纯粹的技术角度来看,HTTP 方法只是一个字符串。理论上,您也可以使用 FETCH /api/v1/users,而不是发送 GET /api/v1/users。实际上,围绕众所周知的 HTTP 方法(例如 GET 和 POST)存在大量 RFC 和隐式的、未记录的行为。例如,当您输入地址或单击书签时,浏览器会发送 GET 请求。标准 HTTP 表单仅允许 GET 和 POST 作为方法。大多数代理、防火墙和网络服务器只允许“标准”HTTP 方法。那么,当我们已经拥有一组运行良好数十年的现有方法时,为什么要引入新的 HTTP 方法呢?使用 GET 进行查询 传统上,如果您想过滤资源,可以在 GET 请求中使用查询参数(例如 /api/v1/users?role=admin&status=active&sort=desc )。这对于简单的过滤器非常有效。然而,当您需要执行复杂的关系查询、深层嵌套或高级逻辑时,URL 会变得庞大、难以阅读,有时会达到浏览器或服务器字符限制。其他潜在问题包括: 发送非 ASCII 或特殊字符作为参数需要对其进行编码,从而增加请求大小 服务器和其他中间件可能会记录请求参数,这在某些情况下可能会出现问题 表达某些数据结构(例如数组)没有明确定义且特定于实现(例如 ?roles[0]=admin&roles[1]=reporter vs ?roles=admin&roles=reporter vs ?roles[]=admin&roles[]=reporter ) 与表达深层嵌套结构相同 既然这些都是将数据作为查询参数发送的缺点,为什么不简单地发送带有 JSON 请求正文的 GET 请求呢?同样,从理论角度来看,这应该可行。没有任何 HTTP RFC 明确禁止在执行 HTTP GET 请求时使用请求正文,但指出不应这样做。因此,各种客户端、代理和 Web 服务器实现以不同的方式处理带有正文的 GET 请求。有些人直接拒绝它们,有些人干脆放弃尸体,而另一些人则解释它。因此,将 HTTP GET 与请求正文结合使用是一个坏主意,例如,位于公司防火墙或其他浏览器后面的用户可能无法使用您的网站。这也是为什么没有新的 RFC 指定 GET 请求现在应该支持请求正文的原因,因为这会破坏许多现有的实现。解决方法:使用 POST 查询​由于使用 GET 发送请求正文可能会带来问题,因此解决方法是使用 POST。虽然 POST 允许请求正文,但它引入了重大的语义问题。 POST 被定义为非幂等的,旨在用于资源创建或处理。虽然这听起来可能不是一个大问题,但在实施时可能会很烦人。失败时自动重试。由于 GET 方法被定义为安全且幂等的,只要服务器实现正确,我们就可以重试失败的请求,而不必担心副作用。它还使得代理或其他中间件无法自动理解该操作是只读的。例如,中间件可能会自动将 GET 请求缓存一段时间,这不适用于 POST 请求。 QUERY 方法 ​ 所有上述原因导致经过多年的讨论后,指定了 QUERY 方法。 QUERY 方法没有什么特别的,RFC 粗略地指出它与 GET 方法类似,但带有请求正文。它应该是安全且幂等的。 QUERY请求可以被缓存,但是实现时必须小心地将请求内容合并到缓存键中。总而言之,它最终为复杂的搜索查询提供了一个合适的 HTTP 方法。 QUERY 陷阱​ 立即将所有搜索相关端点切换为使用 QUERY 可能很诱人。在此之前,您需要考虑一些事项。对 HTTP QUERY 的支持仍然非常有限,并且可能会持续一段时间。可能需要数年时间才能在各地得到充分支持。例如,Kreya 在最近的 1.20 版本中添加了对 HTTP QUERY 的开箱即用支持(尽管之前已经可以发送自定义 HTTP 方法)。其他客户端、代理和网络服务器可能仍会拒绝它。在 URL 参数中包含数据的标准 GET 查询仍然完全没问题。如果不需要立即将它们更改为 QUERY 方法,则保留它们。如果您的用户应该能够共享已过滤数据的链接或为其添加书签,请继续使用 GET 请求。作为 QUERY 请求共享链接不起作用。为 QUE 实现自定义缓存