【问题标题】:REST response code for successful add but failed to return the created object添加成功但返回创建对象失败的 REST 响应代码
【发布时间】:2012-12-06 22:47:02
【问题描述】:

好的。我想知道在这种情况下可能的 HTTP 状态(响应)代码是什么。

比方说,POST /Student/ 创建了一个学生资源。假设有多个表要更新。 Student 资源已创建。

通常,创建资源时,应立即在响应中以200 Successful返回该资源。

但是,假设资源已创建,但当您尝试提取资源(来自数据库的查询)时失败。我们应该返回什么状态码?

   `201 Created`? (No resource)
   '200 Successful`? but without the resource. 
   `500 Internal Server Error`?

还有什么?

我猜这是一个相当普遍的场景。

编辑

我想澄清一下。 首先,创建资源的所有 ONE POST 调用。 响应应为 200,资源对象为 JSON。 但是在检索资源的过程中only出错(资源创建成功)。

无法从数据库中获取资源的原因可能是间歇性的,并且可能与服务器/网络相关,稍后可以识别和修复。但是资源确实创建成功了。

【问题讨论】:

  • 如果查询失败,我会说 500;如果查询没有结果,404.
  • 但是如果我们返回500,客户端如何知道资源是否被创建?
  • 另外,为什么不在创建时返回201 Created
  • 换一种说法,如果资源被创建了,为什么不返回呢?这不构成服务器故障吗?事实上,如果你在一个事务中运行它,你会因为任何错误而中止它,然后返回 500。
  • 我在给@iserni 的评论中提到了可能的原因

标签: php api rest status


【解决方案1】:

假设资源已创建,但是当您尝试拉取资源时(从数据库查询)失败

那么资源没有被创建。它只是看起来。这肯定是服务器端错误,因此是 5xx 代码。

除非有用户提供的参数导致失败,在这种情况下它将是 4xx 代码。

更新:或者如果我误解了,你的意思是创建正常并返回一个资源 ID,然后后续有效的 GET 查询没有找到该资源,好吧,在这种情况下,您的服务器代码有问题,您应该早些发出 5xx 错误。一种解决方法可能是创建资源,从资源创建代码发出查询,然后返回 200 或执行清理、重试或在失败时返回 5xx。但真正应该做的是调查导致资源消失或似乎被创建的原因(例如并发问题、糟糕的事务管理、缓存......)。

一个复杂的场景

REST 服务请求创建资源,服务器接受该请求。服务器本身将请求路由到后端,比如说一个数据库,它返回(给服务器)“OK”和一个资源 ID。然后服务器,以防万一,检查,并询问资源 ID。数据库响应,“没有这样的资源”。

在这种情况下,服务器不能出于良心向其客户端返回 200 代码和资源 ID,除非它有充分的理由怀疑客户端在尝试使用该资源 ID 时会遇到麻烦。之后的错误可能更难发现:可能客户已发送电子邮件或执行了涉及该 ID 的复杂操作。

因此,要么返回 500,要么服务器可以尝试修复这种情况,并在适当和可能的情况下应用以下一项或多项:

  • 稍等片刻(客户端仍在等待!)并检查资源是否重新出现
  • 尝试刷新缓存或以其他方式促使数据库占用资源
  • 使资源无效
  • 删除资源(即使它显然不存在)
  • 记录错误并将详细信息发送给管理员
  • 重复资源创建给定次数(不要太大,否则我们可能会将暂时性问题滚雪球成自我拒绝服务),直到它起作用

如果情况在合理和可容忍的(由客户端)时间内得到解决,则可以使用代码 200 返回工作资源。

当然,上述一切实际发生的原因必须调查和补救。可能需要定期从数据库中清除一些“孤立”资源(这总是一个尴尬的提议)。

【讨论】:

  • 假设存在连接问题或服务器超时。可能有多种原因,不一定非要创建。
  • 即使已创建但查询因任何原因失败,仍然是服务器错误(5xx)而不是用户错误(4xx)。
  • 那么客户端如何知道资源是否被创建?
  • 一开始不是2xx吗?
  • 我试图详细说明这个问题。然而,基本上,我个人的经验法则是永远不要掩饰客户的问题。如果问题已得到解决/补救,则可以不提及它发生的事实(对客户。您仍然需要通知系统管理员)。但是返回“可疑”资源(或“放松”资源测试以减少怀疑)不是我建议做的事情。我宁愿尖叫血腥谋杀并发出 500 错误:-)
【解决方案2】:

你可以选择201 Created,就像it doesn't mandate to return the created entity。如果客户端尝试检索它,它会得到一个500 Server Error

如果您想让客户端知道可能的服务器恶作剧,您可以返回202 Accepted,如it is non-committal

无论你做什么,我建议你让这个资源具有幂等性,因为它似乎有复杂的故障模式,并且客户端可能会重新尝试创建。

【讨论】:

  • 等等,201 实际上确实 需要返回创建的实体(如果不是变体)。并且使用 202 通知可能发生的事故有点扭曲协议......客户端一定是期待 202,即它必须知道它正在提交“批处理”请求。 202 不能用作一种“oopsie”代码 - 或者这是我的解释,无论如何......
  • “响应应该包含一个实体,该实体包含资源特征和位置列表,用户或用户代理可以从中选择最合适的一个。” 202 如果它已创建但不能立即阅读可以被视为扭曲了原始意图(“无法立即执行操作”)。
【解决方案3】:

你说错了:

响应应为 200,资源对象为 JSON。

响应应该是 201 而不是 200 并且应该设置 Location: 标头。无需在响应中包含资源表示。如果你想包含它,并且你的代码看起来像这样:

mysql_query('INSERT ...'); // succeeds
$id = mysql_insert_id(); // succeeds
$result = mysql_query('SELECT ...'); // times out

然后只返回没有正文的 201。如果需要,客户端可以再次尝试获取创建的资源。

【讨论】:

  • 我阅读了大卫的回答,只是觉得需要添加更多内容。他所说的一切也都是正确的 :) 5xx 仅在 INSERT 查询失败时才是正确的,但 POSTed 的参数看起来还不错。显然,用户提供的参数不正确应该会导致您的代码在到达 INSERT 之前以 4xx 退出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-26
  • 2019-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-29
  • 1970-01-01
相关资源
最近更新 更多