19

I have a .NET .ashx handler, which receives a jQuery AJAX post, formats a web service request to a third-party service and consumes the result. On success, it instantiates an anonymous object with the relevant information and formats a JSON response string.

In the event of a web service error, I do the following:

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

This makes both the status code and description easily accessible to the jQuery AJAX error callback; however, the way I have implemented this is quite arbitrary.

After doing some reading around, I can't find a conclusive answer to the following question: Is there an accepted, universal convention (or - even - specification) for returning error states to JSON-based AJAX calls, which allows any consumer to know what to expect, or is this as arbitrary as a return type for any other function call?

So, is this a perfectly acceptable way of returning an error status to the AJAX caller, or is there a "proper" way of formatting a JSON error response?

4

5 回答 5

20

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

状态码

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

201 Created

或者:

200 OK

如果出现验证错误(例如ArgumentException),它可能会执行以下操作:

400 Bad Request

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

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

其他人认为您应该简单地采用 HTTP 协议中未使用的错误状态代码之一,例如461. Twitter 已经做到了这一点(除其他外)420 Enhance Your Calm,以​​通知客户他们现在受到速率限制——即使已经有一个(表面上)可接受的(和推荐的)状态代码429 Too Many Requests用于该目的。

等等。这都是哲学问题。

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

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

回复

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

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

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

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默认执行类似的操作,但属性和内容略有不同。微软自己的 Web API 框架做了类似的事情。相关问题中链接的 JSend 规范是另一种变体。

等等。

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

(是的,这很长——主要是因为我一直在寻找同一种“通用约定”一段时间)。

有关状态码的更多信息,这是一篇很棒的文章(此处引用太长)

于 2013-07-10T15:03:15.360 回答
3

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

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

于 2013-07-10T14:00:58.897 回答
2

我的 2 美分:

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

由于不是 200 的任何内容都是某种错误,并且 http 状态代码有据可查,在这种情况下应该使用它们,因此实际上不需要任何进一步的错误消息(状态代码暗示了错误描述)。浏览器是发出请求的人,他们不关心错误消息,只关心状态码。

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

于 2013-07-10T13:37:00.657 回答
2

Google JSON 样式指南使用数据异或错误对象...

为了跨 API 维护一致的接口,JSON 对象应遵循下面概述的结构。此结构适用于使用 JSON 发出的请求和响应。
              . . .
JSON 对象有一些顶级属性,后跟一个 数据对象或一个错误对象,但不能同时跟上两者。

一个例子...

{
  "apiVersion": "2.0",
  "error": {
    "code": 404,
    "message": "File Not Found",
    "errors": [{
      "domain": "Calendar",
      "reason": "ResourceNotFoundException",
      "message": "File Not Found
    }]
  }
}
于 2013-10-10T05:21:51.120 回答
0

作为实践,我通常采用服务器端系统的名称、结构和内容。

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

因此,例如,如果我向“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 等。

于 2015-06-05T03:30:31.003 回答