REST API 错误返回良好做法 [关闭]

Posted

技术标签:

【中文标题】REST API 错误返回良好做法 [关闭]【英文标题】:REST API error return good practices [closed] 【发布时间】:2010-10-30 21:17:38 【问题描述】:

我正在寻找有关从 REST API 返回错误的良好做法的指导。我正在开发一个新的 API,所以我现在可以采取任何方向。我的内容类型目前是 XML,但我计划将来支持 JSON。

我现在添加一些错误案例,例如客户端尝试添加新资源但已超出其存储配额。我已经在处理某些带有 HTTP 状态代码的错误情况(401 用于身份验证,403 用于授权,404 用于普通错误请求 URI)。我查看了祝福的 HTTP 错误代码,但 400-417 范围似乎都不适合报告特定于应用程序的错误。所以一开始我很想用 200 OK 和一个特定的 XML 有效负载返回我的应用程序错误(即。付给我们更多钱,你会得到你需要的存储空间!)但我停下来想它,它似乎很肥皂(/惊恐地耸耸肩)。此外,感觉就像我将错误响应分成不同的情况,因为一些是 http 状态代码驱动的,而另一些是内容驱动的。

那么行业建议是什么?良好实践(请解释原因!)以及从客户端 pov 来看,REST API 中的哪种错误处理使客户端代码的工作更轻松?

【问题讨论】:

澄清一下:我对返回哪个特定的 HTTP 状态代码不太感兴趣,但是将有效负载错误与 HTTP 状态代码结合起来是否是一种好的 REST 实践,或者更好地单独依赖有效载荷。 The REST API Design Handbook 很好地涵盖了这个主题。 该问题不征求意见,而是征求指导/建议,应重新打开并用作参考。在 2016 年结束这个问题的意义是什么,这个问题是在 2009 年创建的,有 400 多票,没有一个基于意见的现有答案 大多数都没有提到,但是使用 HTTP 错误代码可能会导致关于问题主要原因的问题。 HTTP 是传输协议,404 应该表明 URL 传输级别存在问题(例如,错误的路径)。如果应用程序无法通过其 id 找到数据集,这是一个应用程序级别错误(不是传输级别错误),并且 404,正如 restful http 状态代码用户所建议的那样,可能会导致错误的结论。一般来说,我不喜欢在使用状态码时混淆传输层和应用层。 查看另一个类似主题的答案:***.com/a/63046962/2153237 【参考方案1】:

所以起初我很想用 200 OK 和特定的 XML 有效负载返回我的应用程序错误(即。支付更多费用,您将获得所需的存储空间!)但我停下来考虑它,它似乎肥皂味(/耸耸肩)。

除非请求确实没有问题,否则我不会返回 200。从RFC2616 开始,200 表示“请求成功”。

如果客户端的存储配额已超出(无论出于何种原因),我将返回 403(禁止):

服务器理解请求,但拒绝执行。授权将无济于事,并且不应重复请求。如果请求方法不是 HEAD 并且服务器希望公开请求未完成的原因,它应该在实体中描述拒绝的原因。如果服务器不希望向客户端提供此信息,则可以使用状态码 404(未找到)。

这告诉客户端请求正常,但它失败了(200 不会做的事情)。这也让您有机会在响应正文中解释问题(及其解决方案)。

您还想到了哪些其他具体的错误情况?

【讨论】:

我是否应该在正文中包含我的详细错误消息,即。 XML 代码/字符串对?客户如何最好地处理这个问题?例如,我知道基于 C# WebRequest 的客户端会抛出“错误请求”或“禁止”而不给出响应正文。 403“应该”的正文包含错误的详细信息。客户是否准备好使用这些信息是另一回事。这种格式与所有其他有效负载(例如 XML、JSON)的格式相同是最有意义的。 ... 如果 403 中未返回详细信息,则使用 404“可以”代替(但对我来说这听起来不是最佳选择)。 404 选项适用于 403 可能会泄露您不希望未经授权的用户知道的应用程序详细信息的事件 - 如果非管理员用户点击管理员专用 URL,则例如,您可能不希望该用户知道它是管理员的有效 URL,等等。不过,在这种情况下,403 是完全合适的。 我觉得这是一个非常无益的答案。我本以为更重要的方面是关于是否应单独使用状态,或者是否应在有效负载中返回错误信息,或两者兼而有之,等等。然后如何将信息添加到有效负载中。使用的特定状态仅针对问题的一个特定方面进行磨练。【参考方案2】:

主要的选择是您是否要将 HTTP 状态代码视为 REST API 的一部分。

两种方式都可以正常工作。我同意,严格来说,REST 的一个想法是您应该使用 HTTP 状态代码作为 API 的一部分(成功操作返回 200 或 201,根据各种错误情况返回 4xx 或 5xx。)但是,没有 REST 警察。你可以做你想做的。我见过更多令人震惊的非 REST API 被称为“RESTful”。

此时(2015 年 8 月)我建议您将 HTTP 状态代码用作 API 的一部分。与过去相比,现在使用框架时更容易查看返回码。特别是,现在比过去更容易查看非 200 的返回案例和非 200 响应的主体。

HTTP 状态代码是您的 api 的一部分

    您需要仔细选择适合您的错误条件的 4xx 代码。您可以包含一个 rest、xml 或纯文本消息作为包含子代码和描述性注释的有效负载。

    客户端将需要使用一个软件框架,使他们能够获得 HTTP 级别的状态代码。通常可行,但并不总是直截了当。

    客户端必须区分指示通信错误的 HTTP 状态代码和指示应用程序级问题的您自己的状态代码。

HTTP 状态代码不是您的 api 的一部分

    如果您的应用收到请求然后响应(成功和错误情况),HTTP 状态代码将始终为 200

    您的所有回复都应包含“信封”或“标题”信息。通常是这样的:

    信封版本:1.0
    status: # 使用任何你喜欢的代码。保留成功的代码。
    msg: "ok" # 反映代码的人工字符串。对调试很有用。
    data: ... # 响应的数据,如果有的话。

    这种方法对客户端来说更容易,因为响应的状态总是在同一个地方(不需要子代码),对代码没有限制,不需要获取 HTTP 级别的状态代码.

这里有一个类似想法的帖子:http://yuiblog.com/blog/2008/10/15/datatable-260-part-one/

主要问题:

    请务必包含版本号,以便您以后可以根据需要更改 api 的语义。

    文档...

【讨论】:

泰。选项 2 看起来就像是穿着休息服的肥皂…… 不,通过 200 隧道传输所有内容一点也不平静。它阻止中间人理解操作的结果,这将杀死任何形式的缓存,它隐藏了操作的语义,并且它强制理解消息的内容来处理错误,违反了自包含消息的约束。 返回 200 的错误详细信息可能不是 RESTful,但这仍然是一个有用的答案(如果您忽略“两种方式都很安静”的话)......更大的一点可能是 RESTful API 可能不是 OP 的最佳选择。 似乎有一种普遍的理解,即您可以使用 HTTP 协议做任何您想做的事情,并且仍然是“RESTy”,这是错误的。使用协议编写的内容,这是 REST 的核心思想之一。所以状态码必须是你协议的一部分。 状态码的意义在于在不同的编程语言、框架和方法之间提供一种通用的理解语言。状态码的含义几乎是通用的:您的自定义主体(通过您的 API 使用者必须学习的自定义语法固有地增加了更多复杂性)并非如此。【参考方案3】:

请记住,状态代码比 HTTP/1.1 RFC 中定义的代码更多,IANA 注册表位于 http://www.iana.org/assignments/http-status-codes。对于您提到的状态代码 507 听起来正确的情况。

【讨论】:

嗯,乍一看“507 Insufficient Storage”似乎是合适的,但我对使用它持谨慎态度,因为它是作为(相当具体的)WebDAV 扩展而不是通用的“嘿,你空间不足”例外。不过,我想你可以使用它。 不,它根本不是 WebDAV 特定的。有一个 HTTP 状态代码注册表是有原因的。 我不同意 507 用于此目的。我对507的解释是服务器空间不足,而不是账户空间不足。 我同意帕特里克的观点。 5xx 错误是与服务器有关的错误。 418:“I'm a teapot”表示存储空间太小(就像茶壶一样小)而不是大,因此空间不足。【参考方案4】:

有两种错误。应用程序错误和 HTTP 错误。 HTTP 错误只是让您的 AJAX 处理程序知道一切正常,不应用于其他任何事情。

5xx服务器错误

500 Internal Server Error
501 Not Implemented
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
505 HTTP Version Not Supported
506 Variant Also Negotiates (RFC 2295 )
507 Insufficient Storage (WebDAV) (RFC 4918 )
509 Bandwidth Limit Exceeded (Apache bw/limited extension)
510 Not Extended (RFC 2774 )

2xx 成功

200 OK
201 Created
202 Accepted
203 Non-Authoritative Information (since HTTP/1.1)
204 No Content
205 Reset Content
206 Partial Content
207 Multi-Status (WebDAV)

但是,如何设计应用程序错误完全取决于您。例如,堆栈溢出发送一个具有responsedatamessage 属性的对象。我认为响应包含truefalse 以指示操作是否成功(通常用于写入操作)。数据包含有效负载(通常用于读取操作),消息包含任何其他元数据或有用的消息(例如,responsefalse 时的错误消息)。

【讨论】:

400 也有助于指示客户端应用程序中的问题。【参考方案5】:

不要忘记 5xx 错误以及应用程序错误。

在这种情况下,409(冲突)呢?这假设用户可以通过删除存储的资源来解决问题。

否则 507(不完全标准)也可以工作。我不会使用 200,除非您通常使用 200 来表示错误。

【讨论】:

【参考方案6】:

正如其他人所指出的,在错误代码中包含响应实体是完全允许的。

请记住,5xx 错误是服务器端的,即客户端无法对其请求进行任何更改以使请求通过。如果超出了客户端的配额,那肯定不是服务器错误,所以应该避免 5xx。

【讨论】:

我不同意。 Quota Exceeded 将是一个服务器错误(5xx),因为:客户端的请求是有效的,如果低于配额就会成功,这排除了 400series。 但是服务器并没有做错什么。【参考方案7】:

如果超出客户端配额,则为服务器错误,请避免在这种情况下使用 5xx。

【讨论】:

为什么要避免5xx系列错误,因为它们是服务器错误? 'client quota exceeded' 不是服务器错误恕我直言,这是客户端限制,应低于 4xx。【参考方案8】:

根据现有的“最佳实践”对您的 api 进行建模可能是可行的方法。 例如,这里是 Twitter 处理错误代码的方式 https://developer.twitter.com/en/docs/basics/response-codes

【讨论】:

【参考方案9】:

同意。 REST 的基本理念是使用 Web 基础设施。 HTTP 状态代码是允许各方在不增加 HTTP 有效负载的情况下相互通信的消息传递框架。它们已经建立了传达响应状态的通用代码,因此,要真正实现 RESTful,应用程序必须使用此框架来传达响应状态。

在 HTTP 200 信封中发送错误响应具有误导性,并强制客户端(api 使用者)解析消息,很可能以非标准或专有方式。这也不是有效的——您将强制您的客户端每次解析 HTTP 有效负载以了解“真实”响应状态。这增加了处理,增加了延迟,并为客户创造了一个犯错的环境。

【讨论】:

无论你有一个成功的响应,还是一个失败的响应,你很可能会解析响应。如果是错误,您需要对其进行解析以获取错误消息。错误响应通常很小并且可以快速解析。我认为我们不应该担心尝试优化以避免解析错误响应。你会直接扔掉错误响应而不解析它吗?在我看来是不明智的。 如果您获得 200 OK,您也可以选择不解析它,具体取决于您的业务规则。关键不在于我们是否一直解析它。重点是意图——200 OK 的意图是什么?您通过发送包装在 200 OK 中的错误消息来破坏意图。 "200 OK 的目的是什么?" - 表示传输层成功。请求已成功接收并得到响应,只是一个与 HTTP 无关的应用程序特定问题。 +++ 反过来说:在 REST 世界中发送 404 意味着未找到 something,可能 URL 完全错误,或者未找到要处理的资源或其他任何东西。如果不解析消息,则不能。恕我直言 REST 只是合并层。 合并是常态。它为您提供了一种适合您推理的语法来处理,并使您可以专注于业务层。同意传输后来的状态通信 - 这就是最初的目的 - REST 不是与 HTTP 同时发明/提出的 - 它是后来出现的,只是决定使用现有的基础设施来表示状态及其变化。【参考方案10】:

我知道这对聚会来说已经很晚了,但是现在,在 2013 年,我们有一些媒体类型来涵盖以通用分布式 (RESTful) 方式处理的错误。请参阅“vnd.error”、application/vnd.error+json (https://github.com/blongden/vnd.error) 和“HTTP API 的问题详细信息”、application/problem+json (https://datatracker.ietf.org/doc/html/draft-nottingham-http-problem-05)。

【讨论】:

感谢您的链接。 Draft-nottingham-http-problem 现在是一个提议的标准:datatracker.ietf.org/doc/rfc7807【参考方案11】:

为您的 API 选择正确的 HTTP 错误代码的绝佳资源: http://www.codetinkerer.com/2015/12/04/choosing-an-http-status-code.html

文章摘录:

从哪里开始:

2XX/3XX:

4XX:

5XX:

【讨论】:

422 是专门的 WebDAV 扩展。我认为不应该在这里。 @Mario 在 Ruby on Rails API 中的习惯用法是返回 422 以响应此处指定的条件。遵循这种方法已经有很多好处了。你会用什么来代替 422 的用途? 普通老款 400 谢谢。什么意思是“你愤怒地退出互联网?”? @Crimean.us google.com/search?q=define+rage-quit【参考方案12】:

请遵守协议的语义。使用 2xx 表示成功响应,使用 4xx 、 5xx 表示错误响应 - 无论是您的业务异常还是其他。如果将 2xx 用于任何响应是协议中的预期用例,那么它们首先不会有其他状态代码。

【讨论】:

以上是关于REST API 错误返回良好做法 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

电子中的 REST API [关闭]

Java Rest API - 返回帐户余额的方法[关闭]

Node JS在rest api响应中返回图像[关闭]

Cloudinary REST api 销毁不起作用? [关闭]

当应用程序关闭时,Rest Api Firebase 通知在 Swift 4 中不起作用

将 REST 添加到 Django [关闭]