【问题标题】:REST API - Which Http status codes to use for a booking API?REST API - 哪些 Http 状态代码用于预订 API?
【发布时间】:2021-04-20 20:38:32
【问题描述】:

对于要为我正在构建的 API 返回哪些 HTTP 状态代码感到有些困惑。允许客户查询产品库存和进行租赁预订的 API。

问题是在以下类似情况下什么时候用400s,什么时候用200s:

  1. 最终用户提出了有效的预订请求,但他们所请求的项目在他们选择的日期都已预订完毕。
  2. 最终用户提出了有效的预订请求,但订单日期过早。重要信息:我们需要至少两天通知才能完成订单。
  3. 最终用户尝试在第一次保留我的{orderId}/confirm 端点后的第二天调用它。关键信息:您必须在预订后 15 分钟内确认订单,否则将超时。

请求格式正确,它们引用的资源都存在,那么我们真的可以称它为客户端的错误吗?如果不是,那么返回 400 个代码是否合适?

在这些情况下,您会使用哪种 HTTPStatus? 200 年代的东西还是 400 年代的东西?

【问题讨论】:

标签: spring-boot api rest httpresponse


【解决方案1】:

预订 API 使用哪些 Http 状态代码?

HTTP 状态码属于transfer of documents over a network 域。因此,您使用它们的方式与万维网上的所有其他服务器使用它们的方式完全相同。

status-code 元素是一个 3 位整数代码,描述了服务器尝试理解和满足客户端相应请求的结果。响应消息的其余部分将根据为该状态代码定义的语义进行解释。

特定于您的域的语义不属于 HTTP 标头,而是位于响应的消息正文中。

遵守 REST 架构约束的有用启发式方法:您将如何在 Web 上执行此操作?通常,您打算为人类(理解域上下文的客户端)提供的信息属于 HTML,即 HTTP 响应的正文。元数据(状态代码、标题)为对文档内容不感兴趣的通用组件(浏览器、缓存、网络爬虫)提供语义提示。

问题是在以下类似情况下什么时候用400s,什么时候用200s

考虑cache-invalidation 的规则可能会有所帮助。 TL;DR 是,如果您发送错误状态代码(4xx 或 5xx),则缓存知道响应主体是错误的表示,之前缓存的资源副本仍应被视为有效。

另一方面,2xx 代码报告请求确实成功更改了资源,因此之前缓存的资源副本可能会失效。

POST /orders/12345 HTTP/1.1
Content-Type: application/x-www-form-urlencoded

confirm=yes

如果此消息更改了 /orders/12345 资源,那么您应该倾向于返回 2xx 响应,即使对文档的更改并未反映您域中的“快乐路径”。另一方面,如果资源没有变化,那么 4xx 代码更合适。

status code registry 文档当前定义了每个状态代码的语义。您可以深入了解每个标准,以了解每个标准的不同含义和含义。

但简短的版本是有两个 4xx 代码突出:

  • 403,表示服务器理解请求但拒绝执行。
  • 409,表示由于资源当前状态,服务器无法完成请求。

我在标准中没有发现任何区别对待这两个代码的地方。

我认为您可以提出一个论点,即 409 邀请客户端获取资源的新副本,合并更改,然后重新提交——这与 401 邀请客户端使用授权凭据重新提交请求的方式大致相同.但我从未听说过这样做的通用组件。或许,这有点触手可及。

【讨论】:

    【解决方案2】:

    老实说,REST 在网络上是如此混乱,以至于您会看到两种 API 会返回 200 并出现应用程序层错误,而 API 会在与您的示例类似的情况下返回 400。检查您的选择是否会影响响应是否可以被缓存总是好的,但我假设您无论如何都是POSTing 到这些端点。

    就个人而言,我会推荐 gRPC 采用的方法,即对应用程序和协议错误使用相同的 status,这在大多数 API 中感觉非常一致。阅读那里的错误类型可能有助于了解哪些错误应该是错误的,哪些应该可以,但根据经验,200 OK 应该始终表示“我已满足您的要求”。

    还要注意HTTP RFC 说:

    o 4xx(客户端错误):请求包含错误的语法或不能 完成了

    o 5xx(服务器错误):服务器显然未能满足 有效的请求

    500 空格通常被解释为“这应该有效,但没有因为我们搞砸了(技术问题)”,所以如果您将它们作为 HTTP 代码返回,那么您的所有示例都应该是 400s。

    我很想知道是否有人会持反对意见,但 IMO 使用应用程序错误有点奇怪,因为您现在必须进行双重错误检查和逻辑:

    if (response.getHttpStatus() != HttpCode.OK) {
      handleHttpError();
    } else if (response.getPayload().getStatus() != PayloadCode.OK) {
      handleApplicationError();
    }
    doWork(response.getPayload());
    

    我认为这是有道理的,但如果您使用的框架以一种会导致问题的奇怪方式使用 HTTP 错误,因为框架 400 需要与应用程序 400 不同的处理方式。

    【讨论】:

      【解决方案3】:

      实际上,(不是惯用的)说它会根据您的喜好分解。我会在等式中添加以下问题:

      1. 您将如何根据来自服务器的“错误”响应在客户端上扩展您的逻辑?假设您有几个场景:

        • 特定位置的请求日期已预订(如您所述)
        • 请求的日期可用,但非常有限。因此,来自不同地方的两个用户尝试同时预订同一个地方 -> 一个会出错。
        • 该区域内的所有位置都已预订 ...(你可以想出更多)

        所有这些都需要有不同的错误代码以在 UI 中显示不同的错误消息并用于“跟踪目的”(也许您会看到某个位置在某个时间非常繁忙,例如快速显示“书籍”之类的内容此时”)。请务必在响应正文中包含特定于应用程序的内部代码,以便 UI 可以相应地采取行动。

      2. 您将如何从可观察性的角度跟踪这些错误?您可以说我们所有请求中 95% 的结果都是“200”响应。这是什么意思?我会按如下方式阅读它:“业务逻辑”在大多数情况下都能正常工作。 5% 是需要修复的意外错误(不知何故,用户输入的位置带有破坏验证的非 ASCII 符号等)。相反,如果您看到只有 50% 的响应是“200”,这可能会带来混乱,即使您的业务逻辑工作正常,对吧?您可以做些什么来解决用户输入“不可用”日期的问题? 但是,即使使用 HTTP 错误代码进行业务逻辑,也可以调整这部分可观察性以正确显示您需要的数据。

      正如您可能从上面的陈述中猜到的那样,我更喜欢将 HTTP 错误代码用于非业务逻辑。它也使事情变得清晰,尽管起初有点违反直觉,因为使用 200 来表示不成功的行为。但最终,由您决定。只需确保您的错误代码与您的错误代码保持一致,并充分了解您如何在服务器/客户端生成/处理它们。

      【讨论】:

      • 仅供参考:您的第二点是反对返回 200 并出现应用程序错误的主要论据之一。比您看到 50% 200 更糟糕的是,当您的系统完全中断时,您的所有图表都是绿色的。除非您打破 4xx 和 5xx 之间的分隔,否则错误和被拒绝的请求也不会混合。我还要争辩说,如果用户输入了 50% 的错误日期,那么你的 UI 中就会存在可用性错误,但这不是重点。 @OP:在任何一种情况下,如果它们对您很重要,都应该通过度量来捕获错误详细信息。
      • 不确定我是否遵循当您完全系统中断时如何看到“200”?在后者的情况下,由于“远程系统关闭”、“无法连接到数据库”等,您会以“500”响应。此外,错误!= 500。您也可以有 400 的错误(验证,开启等)。
      • 我猜它定义了如何处理完全中断,但通常假设如果没有请求成功,则表示完全中断。如果您返回 100% 的应用程序错误,无论出于何种原因,您都将经历完全中断。没有人会为您返回 200 号付费。
      猜你喜欢
      • 1970-01-01
      • 2014-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-22
      • 2019-12-15
      • 1970-01-01
      • 2022-01-22
      相关资源
      最近更新 更多