我认为返回有意义的HTTP响应是一个好主意,但我试图找到正确的方法来处理它。
在我的ASP.NET核心Web API应用程序中,端点即API操作方法,只需接收请求,调用我的业务层以获取响应并返回响应。
在业务层,我检查请求是否被授权。如果它没有被授权,我会抛出一个例外,它会引发异常类型,即未经授权的请求,但在这种情况下,我的API端点只返回HTTP 500
。我宁愿返回HTTP 401
。
问题是如何将我的较低级别例外转移到HTTP
状态代码。
两个问题:
HTTP
响应,或者我应该让我的API返回HTTP 500
?< / LI>
答案 0 :(得分:1)
Web API应尽力永远不会返回500
状态代码(内部服务器错误)。如果确实如此,那么您编写的代码就会出现问题。
话虽如此,你不应该抛出一个异常,意图发送回状态代码是一种处理请求的相当差的方法 - 即通过执行全面捕获并使用一些很好的状态代码来掩盖它客户。
您应该在请求中运行所有验证和逻辑,并发回您选择的任何
4xx
状态代码。
基本上,对于Web API,状态代码应为
2XX -- Success //(ex: OK, created, no content, etc)
3XX -- Redirection //(ex: renamed an API's path/url to a new one)
4XX -- Client Error
ex:
405 //Method Not Allowed (ex: client sent a DELETE request to your API)
409 //Conflict
415 //Unsupported Media Type (ex: client requests for XML -- yuck! no!)
416 //Range Not Suitable (ex: client asked for a million records)
422 //Unpronounceable Entity (ex: client sent something invalid in the body)
5XX -- Server Error //(ex: a well written Web API will NEVER error! )
但是,如果您确实有异常,那么500
错误代码是正确的 - 这意味着您编写了错误代码(请参阅我的第一点)。
答案 1 :(得分:1)
假设你的控制器扩展了Microsoft.AspNet.MVC.Controller,你将继承一些你需要的方法,如OK,Forbidden,BadRequest,ObjectResult等。所以在你上面描述的情况下,你可以做点什么
public async IActionResult DoMyThing()
{
try
{
return ObjectResult(await DoMyInternalCall());
}
catch (Exception e)
{
//FigureOut the Exception type indications a security violation
return Forbidden()
}
....
我个人更喜欢构建返回状态而不是抛出异常的API,这使得这一切都变得更加清晰,特别是现在我们有了元组。像
这样的东西public async IActionResult DoMyThing()
{
var (Status status, string myThing) = await DoMyInternalCall();
switch(status)
{
case Status.OK: return ObjectResult(myThing);
break;
case Status.AccessDenied: return Forbidden();
break;
case Status.NotFound: return Notfound();
...
这只是一种味道 - 我不判断。关键是,Microsoft.AspNet.MVC.Controller内置了一些方法,可以让您返回有效的HTTP状态代码和数据。
答案 2 :(得分:0)
当然,有大量的HTTP响应代码,仅仅因为请求无法正确处理并不一定意味着它是500内部服务器错误。如果有人请求更新不存在的对象怎么办?这不会落在500的范围内(不确定的副手准确哪个会起作用 - 我猜错4xx,但是当你正在研究这个时,会推荐一个方便的常见HTTP响应列表) 。我一般觉得500多岁是为了#哦;哦,我们结束时发生了什么事,我们不知道是什么......&#34;事物的类型。对于大多数其他情况,有更合适的反应。
话虽如此,我觉得异常最为普遍,因为它们进一步向顶层移动。实体框架引发了一些深奥的异常,数据访问层将其包装在稍微更通用的DataAccessException中(当然,原始内部为),存储库可能更一般地处理它,并且当它到达你的控制器时对于响应处理,你应该只有少数&#34;实际&#34;应该处理的例外情况。返回一些相当通用的东西,在服务器上记录嵌套异常,然后从那里开始?
My 2cents
答案 3 :(得分:0)
我不喜欢这种抛出异常的想法。 500表示您自己的代码确实存在问题。
因此,我们假设您的业务层正在检查用户是否获得授权。我要做的是创建一个检查授权的方法,让该方法返回一个简单的布尔响应,例如。然后你的控制器检查标志,如果它是假的,返回401,完成工作。这是在业务层和api层之间进行通信的更好方法。
显然,我无法知道您的业务层是如何构建的,但要保持简单,保持清晰,不要尝试捕获任何异常,干净地处理所有内容并返回适当的HTTP代码。
业务层不应该关心api,不应该处理HTTP代码,基本上这意味着你不会在任何地方泄露抽象,而是将事物保存在它们所属的层中。