是否有从 JSON Web 服务返回错误状态的传统方法
本文关键字:状态 错误 传统 方法 返回 服务 JSON Web 是否 | 更新日期: 2023-09-27 18:19:58
我有一个.NET .ashx处理程序,它接收jQuery AJAX帖子,格式化对第三方服务的Web服务请求并使用结果。成功后,它会使用相关信息实例化匿名对象,并格式化 JSON 响应字符串。
如果发生 Web 服务错误,我会执行以下操作:
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.StatusDescription = wsResult.ErrorCode;
这使得状态代码和描述都很容易被jQuery AJAX错误回调访问;但是,我实现它的方式是相当随意的。
在做了一些阅读之后,我找不到以下问题的决定性答案:是否有一个公认的通用约定(或 - 甚至 - 规范(将错误状态返回到基于 JSON 的 AJAX 调用,它允许任何消费者知道会发生什么,或者这是否像任何其他函数调用的返回类型一样任意?
那么,这是向 AJAX 调用方返回错误状态的完全可接受的方式,还是格式化 JSON 错误响应的"正确"方法?
正如其他人所说,没有普遍的惯例。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
来通知客户他们现在受到速率限制 - 即使已经有一个(表面上(可接受的(和推荐的(状态代码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 执行类似操作,但属性和内容略有不同。Microsoft自己的Web API框架也做了类似的事情。相关问题中链接的 JSend 规范是另一种变体。
等等。
简而言之,不,没有任何普遍的约定——至少现在还没有。很多人(比我考虑得更多(都在研究它。但是,可能永远不会有。你的方法是完全可以接受的。
(是的,这非常冗长 - 主要是因为我一直在寻找同一种"普遍惯例"一段时间(。
有关状态代码的更多信息,这是一篇出色的文章(太长了,无法在此处引用(
不,没有任何单一的主要标准,尽管这可能很好。如果您正在为自己制定包含 success
和 details
的标准,这可能会很有用,但这取决于您如何使用它。我认为最大的优势是,当您至少在自己的所有代码中实现标准以保持一致性时,例如 http://ricardocovo.com/2012/03/08/asp-net-mvc-using-json-standard-responses-for-your-ajax-calls/
如果符合您的需求,您的回答是完全可以接受的。如果我使用 API,我会看到该错误响应是"标准"的,包含响应代码和描述,尽管我可能想要一个布尔success
以方便使用。
我的 2 美分:
我想说的是,最重要的是,您作为响应发回的状态代码是最好的错误指示器,并在 4xx 和 5xx 范围内提供了很多选项......(即使你尝试从茶壶中获取一些咖啡,你也可以使用418:D(
由于任何不是 200 的东西都是某种错误,并且 http 状态代码有很好的文档记录,在这种情况下应该使用它们,因此任何进一步的错误消息都不是真正必要的(状态代码隐含了错误描述(。浏览器是执行请求的人,它们不关心错误消息,只关心状态代码。
任何额外的错误消息也可能只是为可能的黑客尝试提供了太多信息。我的意思是,返回 403 禁止本身就足够了,您也不应该返回一条消息说"不允许,请使用'1234'作为密码" :)
谷歌 JSON 风格指南使用数据 xor 错误对象......
为了在 API 之间保持一致的接口,JSON 对象应遵循下面概述的结构。此结构适用于使用 JSON 发出的请求和响应。
。
JSON 对象具有一些顶级属性,后跟 数据对象或错误对象,但不能同时使用两者。
一个例子...
{
"apiVersion": "2.0",
"error": {
"code": 404,
"message": "File Not Found",
"errors": [{
"domain": "Calendar",
"reason": "ResourceNotFoundException",
"message": "File Not Found
}]
}
}
我通常采用服务器端系统的名称、结构和内容作为实践问题。
这种做法确保前端开发人员使用他们已经理解的词汇与后端开发人员进行通信,并且它不会设置一个标准/先例,即后端开发人员的任务是实现新格式,因为前端开发人员和设计人员发明了新概念(错误就是错误,我们不要在"类型"和"元"上分裂头发,它们只是任何给定错误的属性。
因此,例如,如果我将错误详细信息返回到"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 等。