是否有从 JSON Web 服务返回错误状态的常规方法?

Posted

技术标签:

【中文标题】是否有从 JSON Web 服务返回错误状态的常规方法?【英文标题】:Is there a conventional way of returning error statuses from JSON web services? 【发布时间】:2013-06-22 01:11:11 【问题描述】:

我有一个 .NET .ashx 处理程序,它接收一个 jQuery AJAX 帖子,格式化一个对第三方服务的 Web 服务请求并使用结果。成功后,它会使用相关信息实例化一个匿名对象并格式化 JSON 响应字符串。

如果出现 Web 服务错误,我会执行以下操作:

context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.StatusDescription = wsResult.ErrorCode;

这使得 jQuery AJAX 错误回调可以轻松访问状态代码和描述;但是,我实现这一点的方式非常随意。

在做了一些阅读之后,我找不到以下问题的结论性答案:是否有一个公认的通用约定(或 - 甚至 - 规范)用于将错误状态返回到 JSON -基于 AJAX 调用,它允许任何消费者知道会发生什么,或者这是否与任何其他函数调用的返回类型一样任意?

那么,这是向 AJAX 调用者返回错误状态的一种完全可以接受的方式,还是有一种“正确”的方式来格式化 JSON 错误响应?

【问题讨论】:

请看看这是否有帮助***.com/questions/12806386/… 【参考方案1】:

正如其他人所说,没有通用约定。 REST“社区”仍在就这些问题寻找一些共识——可能永远也找不到共识。举几个例子:

状态码

默认情况下,ServiceStack.NET(一个广泛使用的 C# REST 库 Web 服务框架)返回带有状态码的对象(或空响应),例如:

201 Created

或者:

200 OK

在验证错误的情况下(例如ArgumentException),它可能会这样做,例如:

400 Bad Request

这已经是事情开始发生变化的第一个点。有些人喜欢 400 状态代码来表示验证错误之类的事情 - 其他人则不喜欢,因为 400 确实在请求格式本身中表示格式错误的语法

有些人更喜欢 422 Unprocessable Entity 验证错误,它是 HTTP 协议的 WebDAV 扩展,但在技术上仍然完全可以接受。

其他人认为您应该简单地采用 HTTP 协议中未使用的错误状态代码之一,例如461。 Twitter 已经通过(除其他外)420 Enhance Your Calm 来通知客户他们现在受到速率限制 - 即使有一个 (表面上) 可接受(和推荐)状态代码 @987654334 @ 已经为此目的了。

等等。这都是哲学问题。

至于500 Internal Server Error,同样适用——有些人认为它对于各种错误响应都很好,其他人认为5xx错误应该在异常时返回(实际上意义 - 即异常错误)。如果错误确实是异常的,那么您通常不想冒险并传递任何实际的异常信息,这可能会透露太多有关您的服务器的信息。

引导我们在 JSON 结果中返回什么(如果有的话)?一样的……

回应

200 OK 可能足以响应例如如果没有发生错误,则请求删除资源。同样,404 Not Found 足以告诉客户端由于找不到要删除的实体而无法执行请求的删除。在其他情况下,您可能需要更多。

有些人认为您应该在响应标头中包含尽可能多的所需信息,通常是只有标头的空响应。例如,在创建时,返回 201 Created 并将创建的实体的 ID(作为资源 URI)放入 Content-Location。无需响应内容。

我个人认为,如果您要创建公共 API,最好同时返回适当的标头和内容,即使内容有些多余。即:

HTTP/1.1 404 Not found
Content-Type: application/json; charset=utf-8
...


   'Success': false,
   'Message': 'The user Mr. Gone wasn't found.'

(我实际上并没有包含 Success 属性,但我可能想要,这取决于我在设计 API 时的心态)。

在调试模式下运行时,我还包括内部服务调用的字符串表示 - 例如'Request': 'GetUser id: 5 '时间戳和堆栈跟踪。不过,这一切都是为了方便。只需基于404 Not found,就可以很容易地为客户端编写适当的用户友好错误消息。不过,其他一些错误(例如验证)可能需要更多上下文。例如:

HTTP/1.1 422 Validation Error
Content-Type: application/json; charset=utf-8
...


   'Success': false,
   'Message': 'The request had validation errors.',
   'Errors':
   
       'UserName': 'The user name must be provided.',
       'Email': 'The email address is already in use.'
   

ServiceStack.NET 支持something like this by default,但属性和内容略有不同。微软自己的 Web API 框架does something similar。 related question 中链接的 JSend 规范是另一种变体。

等等。

简而言之,不,没有任何通用约定 - 至少现在还没有。很多人(比我投入更多的想法)正在研究它。但是,可能永远不会有。而且你的方法完全可以接受。

(是的,这很长 - 主要是因为我一直在寻找相同类型的“通用约定”)。

有关状态码的更多信息,this is an excellent article (too long to quote here)

【讨论】:

优秀的答案,值得赏金。 +1 太棒了。试图回答这个问题一直让我对我当前的项目很生气,我一直在来回思考如何处理这些错误(一些例外,一些我们 - 调用者 - 不一定能预测的验证错误)。很高兴看到我不是唯一一个渴望在这里举行会议的人! 此外,这个答案(以及这里的其他答案)已经触及作为“标准化”JSON响应格式的一部分返回“成功”属性 - 我想在没有通用标准的情况下“内部" 标准就足够了。 是的,这个主题真的可以成为整本书的基础。 :-) 我会支持某人所说的......某处,并推荐像 Swagger 这样的东西来记录 API。正如我所提到的,“成功”属性可以被认为是多余的,当你得到一个 4xx/5xx 响应时,我现在正在设计的 API 中没有它——但是——没有任何真正的理由- 有时我只是喜欢让 JSON “自包含”。感谢您的赏金! :-)【参考方案2】:

不,没有任何单一的主要标准,尽管这可能很好。如果您让自己成为包含successdetails 的标准,这可能会很有用,但这取决于您如何使用它。我认为最大的优势是当您至少在所有自己的代码中实施标准以保持一致性时,例如http://ricardocovo.com/2012/03/08/asp-net-mvc-using-json-standard-responses-for-your-ajax-calls/

如果您的回复符合您的需要,则完全可以接受。如果我正在使用 API,我会将该错误响应视为“标准”,其中包含响应代码和描述,但为了便于使用,我可能希望使用布尔值 success

【讨论】:

【参考方案3】:

我的 2 美分:

我想说的是,作为响应发回的状态码最重要的是最好的错误指示器,并在 4xx 和 5xx 范围内提供了很多选项......(即使你尝试从茶壶中 HttpGET 一些咖啡,你可以使用 418 :D)

因为任何不是 200 的东西都是某种错误,并且 http 状态代码有很好的文档记录,在这种情况下应该使用它们,因此实际上不需要任何进一步的错误消息(状态代码暗示了错误描述)。浏览器是发出请求的,它们不关心错误消息,只关心状态码。

任何额外的错误消息也可能会为可能的黑客攻击提供太多信息。我的意思是,返回 403 Forbidden 本身就足够了,您不应该还返回一条消息说“不允许,请使用 '1234' 作为密码”:)

【讨论】:

这是我的问题的症结所在,我想 - 所讨论的错误不是异常的“通用错误响应”,但实际上具有需要传达给用户的语义含义。【参考方案4】:

Google JSON Style Guide 使用 data xor error 对象 ...

为了在 API 之间保持一致的接口,JSON 对象应遵循下面概述的结构。此结构适用于使用 JSON 发出的请求和响应。 . . . JSON 对象有一些***属性,后跟一个 data 对象或 error 对象,但不能同时使用。

一个example ...


  "apiVersion": "2.0",
  "error": 
    "code": 404,
    "message": "File Not Found",
    "errors": [
      "domain": "Calendar",
      "reason": "ResourceNotFoundException",
      "message": "File Not Found
    ]
  

【讨论】:

【参考方案5】:

我一般习惯性地采用服务器端系统的名称、结构和内容。

这种做法可确保前端开发人员使用他们已经了解的词汇与后端开发人员进行交流,并且它并没有设定一个标准/先例,让后端开发人员负责以前端开发人员的身份实现新格式并且设计师发明了新概念(错误就是错误,我们不要对“类型”和“元”分心,它们只是任何给定错误的属性。)

因此,例如,如果我向“JSON 客户端”返回错误详细信息,并且服务端点是使用 C# 实现的,我希望返回如下所示的 JSON 文档:

 
  "Message": "An error has occurred.", 
  "ExceptionMessage": "Index was outside the bounds of the array.", 
  "ExceptionType": "System.IndexOutOfRangeException", 
  "StackTrace": "   at WebApiTest.TestController.Post(Uri uri) in c:\\Temp\\WebApiTest\\WebApiTest\\TestController.cs:line 18\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClassf.<GetExecutor>b__9(Object instance, Object[] methodParameters)\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)\r\n   at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)",

当然,不要模仿公认的答案,我只想传达统一的价值是巨大的,特别是如果你是一个多语言的人(或者“一个全新的程序员”,他们根本不确定一种方式或另一个。)

现在对您来说可能无关紧要,但在 2、3 或 5 年的维护之后,您可能会开始关心,并且您可能会发现从长远来看,当您遇到其他拥抱类似的从众实践,并且您是团队中唯一仍在尝试发明新格式的人(当没有必要时)。

注意为了清楚起见,我并不是建议您将异常序列化到客户端。虽然,这在许多情况下可能是一个完全有效的选择,包括调试、安全私有云或没有敏感数据/IP 等。

【讨论】:

以上是关于是否有从 JSON Web 服务返回错误状态的常规方法?的主要内容,如果未能解决你的问题,请参考以下文章

HTTP常见错误返回代码

使用 Play 以 JSON 形式返回验证错误!框架

AngularJS $http 获取返回空状态 0

如何将 json 数据返回到反应状态?

HTTP TFP状态解释

Ext JS 5 关于Store load返回json错误信息或异常的处理