我有一个.NET .ashx处理程序,它接收一个jQuery AJAX帖子,将Web服务请求格式化为第三方服务并使用结果。成功时,它会使用相关信息实例化一个匿名对象,并格式化JSON响应字符串。
如果出现Web服务错误,我会执行以下操作:
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.StatusDescription = wsResult.ErrorCode;
这使得jQuery AJAX错误回调可以轻松访问状态代码和描述;但是,我实现这一点的方式非常随意。
在做了一些阅读之后,我无法找到以下问题的结论性答案:是否存在可接受的通用约定(或 - 甚至 - 规范),用于将错误状态返回到基于JSON的AJAX调用,它允许任何消费者知道会发生什么,或者这对任何其他函数调用都是任意的返回类型?
那么,这是一种将错误状态返回给AJAX调用者的完全可接受的方式,还是有一个"正确的"格式化JSON错误响应的方法?
答案 0 :(得分:20)
正如其他人所说,没有普遍的惯例。 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
做了这件事,通知客户他们现在正在受到速率限制 - 即使有(表面上)可接受(和推荐)状态代码{G}已为此目的429 Too Many Requests
。
等。这完全是哲学问题。
对于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时,我可能想要这取决于我的心态。)
在DEBUG模式下运行时,我还包括内部服务调用的字符串表示 - 例如'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,但属性和内容略有不同。 Microsoft自己的Web API框架does something similar。 related question中链接的JSend规范是另一种变体。
等等。
简而言之,不,没有任何普遍的惯例 - 至少还没有。很多人(比我更多地考虑它)正在努力。但是,仍然可能永远不会。而你的方法是完全可以接受的。
(是的,这是非常冗长的 - 主要是因为我一直在寻找相同类型的“普遍惯例”)。
有关状态代码的更多信息,请this is an excellent article (too long to quote here)
答案 1 :(得分:3)
不,没有任何单一的主要标准,尽管这可能很好。如果您使自己成为包含success
和details
的标准可能会有用,但这取决于您使用它的确切方式。我认为最大的好处是,当您至少在所有代码中实现标准以保持一致性时,例如http://ricardocovo.com/2012/03/08/asp-net-mvc-using-json-standard-responses-for-your-ajax-calls/
如果符合您的需求,您的回复是完全可以接受的。如果我正在使用API,我会将错误响应视为“标准”,包含响应代码和描述,尽管我可能希望使用布尔success
以便于使用。
答案 2 :(得分:2)
我的2美分:
我会说最重要的是你发回的状态代码,因为响应是最好的错误指示器,并在4xx和5xx范围内提供了很多选项...(即使你试图从茶壶中取出一些咖啡,你可以使用418:D)
由于任何不是200的内容都是某种错误,并且http状态代码已经很好地记录了,在这种情况下应该使用它们,任何进一步的错误消息都不是必需的(状态代码隐含了错误描述)。浏览器是执行请求的人,他们不关心错误消息,只关心状态代码。
任何额外的错误消息也可能只是为了可能的黑客攻击而提供太多信息。我的意思是,返回403 Forbidden本身就是足够的信息,你也不应该回复一条消息“不允许,请用'1234'代替密码”:)
答案 3 :(得分:2)
Google JSON Style Guide 使用 data xor error 对象......
为了在API之间保持一致的接口,JSON对象应遵循下面概述的结构。此结构适用于使用JSON进行的请求和响应 。 。 。
JSON对象有一些顶级属性,后跟a data 对象或 error 对象,但不是两者。
example ...
{
"apiVersion": "2.0",
"error": {
"code": 404,
"message": "File Not Found",
"errors": [{
"domain": "Calendar",
"reason": "ResourceNotFoundException",
"message": "File Not Found
}]
}
}
答案 4 :(得分:0)
我通常采用服务器端系统的名称,结构和内容作为实践。
这种做法可确保前端开发人员使用他们已经理解的词汇表与后端开发人员进行通信,并且它没有设置标准/先例,后端开发人员的任务是将新格式作为前端实现 - 最终的开发人员和设计人员发明了新的概念(错误是一个错误,让我们不要分开关于&#34;类型&#34;和#34;元&#34;,它们只是任何给定错误的属性。 )
因此,例如,如果我将错误详细信息返回给&#34; JSON客户端&#34;并且使用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)",
}
当然,不要嘲笑接受的答案,我只想表达一致性的价值是巨大的,特别是如果你是一个多语言(或者是一个全新的程序员&#34;谁是根本不确定这种或那种方式。)
现在对你来说可能没关系,但是在2年,3年或5年的维护中你可能会开始关心,你可能会发现自己必须重新训练&#34;从长远来看,当你遇到其他开发人员,他们采用类似的一致性做法时,你是团队中唯一仍然试图发明新格式的人(如果没有必要的话)。
注意:要明确我不建议您将异常序列化到客户端。虽然,在许多场景中这可能是一个非常有效的选择,包括调试,安全私有云,或者没有敏感数据/ IP等等。