2017-10-07 67 views
-1

我觉得返回有意义的HTTP响应是个好主意,但我试图想出正确的方法来处理这个问题。在ASP.NET Core 2.0 Web API中返回有意义的HTTP响应

在我的ASP.NET Core Web API应用程序中,端点(即API操作方法)仅接收请求,调用我的业务层以获取响应并返回响应。

在业务层,我检查请求是否被授权。如果它没有被授权,我会抛出一个例外,它包含了未授权的请求类型,但在这些情况下,我的API端点只返回HTTP 500。我宁愿退还HTTP 401

问题是如何将我的较低级别例外转换为HTTP状态代码。

两个问题:

  1. 是否值得试图捕捉例外发生在应用中的较低水平的类型,并尝试将其翻译为HTTP反应,或者我应该只是让我的API返回HTTP 500
  2. 如果值得,我该如何处理?
+0

因此,在5xx与4xx之间进行讨论与错误消息的回应是错误的。 –

+0

@Sam - 我同意阿列克谢,这个问题在这里脱离主题。然而,如果你重新提出问题来问“怎么做”而不是“我应该”这样做,这将是一个合理的问题。 – NightOwl888

回答

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状态代码和数据。

+0

这就是我一直在寻找的东西。谢谢! – Sam

0

当然有很多HTTP响应代码,只是因为请求无法正确处理并不一定意味着它是500内部服务器错误。如果有人要求更新一个不存在的对象会怎么样?这不会落在500的范围之内(不确定哪一个可以正常工作 - 我猜可能是4xx,但推荐使用这个常用的HTTP响应列表)。我通常认为,500人是为了“呃,发生在我们身上的事情,我们不知道...”类型的事情。对于大多数其他情况,还有更合适的回应。

就这样说,我觉得例外是最好的概括,因为他们进一步走向顶层。实体框架引发了一些深奥的异常,数据访问层将其包装在一个稍微更通用的DataAccessException中(当然,原始内部为原始),存储库可能更加通用地处理它,并且在它到达控制器时对于响应处理,您应该只有少数应该需要处理的“实际”异常。返回相当通用的东西,在服务器上记录嵌套的异常,并从那里去?

我的2分钱小费

0

一个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错误代码是正确的 - 这意味着你写不好的代码(请参考我的第一点)。

+0

您是否在说我应该检查用户是否在API级授权,而不是在业务层? – Sam

+0

@Sam我不能确定根据提供的信息,但实际上你应该试图在每一层进行验证。永远不要假设层之间的数据是有效的。 – Svek

+0

@Sam通常越早,您可以阻止**请求**,使其沿请求管道向下传递(每层进一步传递)越好。这意味着大多数例外不太可能首先发生。 – Svek

0

我不喜欢这种抛出异常的想法。 500是一个标志,说明你自己的代码有一些错误。

因此,假设您的业务层正在检查用户是否被授权。我会做的是创建一个方法来检查授权,让该方法返回一个简单的布尔响应,例如。然后你的控制器检查标志,如果它是假的,返回401,完成工作。这是在业务层和api层之间进行通信的更好方式。

很明显,我无法知道您的业务层是如何构建的,但保持简单,保持清晰,不要试图捕获任何异常,干净地处理所有内容并返回适当的HTTP代码。

业务层不应该关心api,不应该处理HTTP代码,基本上这意味着您不会在任何地方泄漏抽象,并且将事物保留在它们所属的层中。

相关问题