4

假设我有一个将用户绑定到公司的 RESTful API:

PUT http://example.com/users/john.smith

{
  "company": "http://example.com/companies/Nintendo"
}

但引用的公司不存在(可能是由于竞争条件,也可能是由于用户错误)。该操作无法成功完成,因为数据库需要外键指向现有行。什么是适当的响应代码,为什么?

4

3 回答 3

2

这绝对是一个4xx错误,因为客户提供的信息是问题的根源。

由于我们正在处理语义性质的问题,HTTP 1.1 的 WebDAV422是最适合的响应代码:

422 Unprocessable Entity (WebDAV)

422 (Unprocessable Entity)状态码意味着服务器理解请求实体的内容类型——因此415 (Unsupported Media Type)状态码是不合适的——并且请求实体的语法正确的——因此400 (Bad Request)状态码是不合适的——但无法处理包含的指令。例如,如果 XML 请求正文包含格式正确(即语法正确)但语义错误的 XML 指令,则可能会发生这种错误情况。

当然,不要让您的客户独自一人在黑暗中,并确保您在响应正文中解释错误发生的原因。


现在讨论一下为什么不是其他代码,首先是三个更令人困惑的,然后是其余的:

  • `400 Bad Request`: *由于语法错误,服务器无法理解请求。客户端不应该在没有修改的情况下重复请求。* - 语法没问题(请求格式正确)。该错误是语义错误(公司不存在)。此外,客户可以在其他时间(添加公司后)重复请求**无需**修改,它可能会起作用。所以,不是400。

  • `403 Forbidden` *服务器理解请求,但拒绝执行。授权将无济于事,并且不应重复请求*:这通常在客户端通过身份验证但缺乏对请求资源的权限(写入、读取或其他要求)时发出。也不是 403。

  • `404 Not Found` *服务器没有找到任何匹配Request-URI*的东西:注意错误是关于**Request-URI**的,也就是用户。当 **user**(URI 中的那个)不存在时,应发送此响应,而不是公司。
  • 和其他人:

  • `401 Unauthorized` *请求需要用户认证*:这里无需争论。
  • `402 Payment required` *此代码保留供将来使用*:此处均无。
  • `405 Method Not Allowed`:与 HTTP 方法无关(`GET`、`PUT` 等)。
  • `406 Not Acceptable`:这与接受标头有关。
  • `407 Proxy Authentication Required`:代理相关。
  • `408 Request Timeout`:显然不是。
  • `409 Conflict`: *由于与资源的当前状态冲突,请求无法完成。*当前(之前保存的)资源(用户的公司)在服务器中是正常的。任何新公司都是可以接受的,新公司和当前公司之间不能有冲突,因为新公司总是会覆盖当前公司。
  • `410 Gone`:*请求的资源在服务器上不再可用,并且不知道转发地址。*与此无关。
  • `411 Length Required`:关于 `Content-Length` 标头。
  • `412 Precondition Failed`:关于请求标头字段。
  • `413 Request Entity Too Large`:与实体的大小无关。
  • `414 Request-URI Too Long`:也不是 URI 的大小。
  • `415 Unsupported Media Type`:请求中的实体正常(服务器知道 JSON)。
  • `416 Requested Range Not Satisfiable`:关于 `Range` 请求标头。
  • `417 期望失败`:关于 `Expect` 请求标头。
  • `423 Locked (WebDAV)` *423 (Locked) 状态码表示方法的源或目标资源已锁定*:此处没有锁定任何内容。
  • `424 Failed Dependency (WebDAV)` *424(Failed Dependency)状态码表示方法无法在资源上执行,因为请求的操作依赖于另一个操作并且该操作失败*:在当前上下文。
  • 于 2013-05-19T20:13:56.147 回答
    1

    我会返回一个HTTP 400 - Bad Request,可能会在响应正文中添加一些提示(例如,Nintendo 不是一个有效的选项)。这不是404 - Not found错误,因为 URL 和其中引用的资源是正确的。

    作为关于您的请求正文的旁注

    {
      "company": "http://example.com/companies/Nintendo"
    }
    

    我希望用户只传递一个名称或关于公司的 id,而不是整个 URI。你增加了更多的复杂性,却不可能获得任何东西。想象一下,一个用户在一个有错字的 URI 中传递了一个有效的公司名称,例如Sega,例如comp panies。我猜你的后端会尝试访问这个 URI,如果失败了,它会返回一个错误。好吧,你可以,但对我来说,你似乎让你和你的用户都过得很艰难。

    于 2013-05-19T09:04:47.383 回答
    0

    如果服务器没有响应,您可以返回 404,如果它确实响应错误,我会返回该错误。

    404 通常是一个永久性错误,在几秒钟内重试后不会消失。

    http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

    于 2013-05-19T08:14:50.880 回答