在ASP.NET Core 2.0 Web API中返回有意义的HTTP响应

时间:2017-10-07 17:41:50

标签: c# api asp.net-web-api asp.net-core asp.net-core-2.0

我认为返回有意义的HTTP响应是一个好主意,但我试图找到正确的方法来处理它。

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

在业务层,我检查请求是否被授权。如果它没有被授权,我会抛出一个例外,它会引发异常类型,即未经授权的请求,但在这种情况下,我的API端点只返回HTTP 500。我宁愿返回HTTP 401

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

两个问题:

  1. 是否值得尝试捕获应用中较低级别发生的异常类型并尝试将其转换为HTTP响应,或者我应该让我的API返回HTTP 500?< / LI>
  2. 如果值得,我该如何处理?

4 个答案:

答案 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代码,基本上这意味着你不会在任何地方泄露抽象,而是将事物保存在它们所属的层中。