【问题标题】:Web Api always returns http status code 200 when an exception occurs发生异常时,Web Api 总是返回 http 状态码 200
【发布时间】:2015-10-28 16:54:09
【问题描述】:
public class GlobalExceptionHandler : ExceptionHandler
{
    public override void Handle(ExceptionHandlerContext context)
    {

        context.Result = new NiceInternalServerExceptionResponse("The current operation could not be completed sucessfully.);
    }
}

当调用此 Get 操作时:

        [HttpGet]
        public async Task<IHttpActionResult> Get()
        {
            Convert.ToInt16("this causes an exception state");
            var data = await service.Get();
            return Ok(data);
        }

引发了异常...并触发了我的全局 exc 处理程序。

当我的自定义响应返回给客户端时,我的提琴手总是说:

结果:200

我也可以将return Ok(data); 更改为return NotFound();

这不会改变结果状态代码中的任何内容。

如何覆盖/拦截 http 状态创建并返回我自己的状态码 500?

在我的网络客户端上,只有在返回状态代码 500 时,我才需要显示一个带有日志记录 ID + 错误消息的漂亮错误对话框。

【问题讨论】:

    标签: c# asp.net-web-api asp.net-web-api2


    【解决方案1】:

    我是这样做的……

        [HttpPost]
        public HttpResponseMessage Post()
        {
            try
            {
                // Do stuff
            }
            catch (Exception ex)
            {
                // Something went wrong - Return Status Internal Server Error
                return new HttpResponseMessage(HttpStatusCode.InternalServerError);
            }
        }
    

    Get 的工作方式相同。

    【讨论】:

    • 我不会在操作中捕获异常,因为这是一个横切关注点,应该与 Web api 管道集成,就像我对全局异常处理程序所做的那样。
    • @Elisabeth 您仍然应该在操作方法中抛出异常,因此全局异常主要用于记录目的。当参数为空、未格式化等时,您将如何验证参数并引发异常?
    • @Teomanshipahi 如果我理解正确:当传递无效参数时,我的通用模型验证将在返回 BadRequest (400) 的操作过滤器中执行。无需抛出异常。永远不需要抛出内部服务器错误异常。它们只是发生并且不再被记录。如果您想捕获和处理操作中发生的业务异常,请使用异常过滤器并返回适当的响应。
    • @Teomanshipahi 我知道那个链接。我所说的都在那个链接里面。我不会抛出“抛出新的 HttpResponseException(HttpStatusCode.NotFound);”一个动作里面。如果在 Repository 中找不到资源,则 Repository 必须抛出 ResourceNotFoundException,该异常被 ExceptionFilter 捕获。
    • @Elisabeth 不同意这一点。存储库的责任是对数据源的 CRUD。它应该捕获并抛出与数据相关的异常。 (数据库连接、存储过程异常等。)如果存储库没有找到结果(这不是异常),则返回 null 或空列表,并且(Web API)将异常作为未找到的内容抛出。您只是出于所有目的将所有异常传递到一个字段中,这对我来说并不好。
    【解决方案2】:

    您可以将下一个代码用于自定义错误:

    return Content(HttpStatusCode.NotFound, "Foo does not exist.");
    

    【讨论】:

      【解决方案3】:

      您需要在IHttpActionResult上设置状态码:

      public class NiceInternalServerExceptionResponse : IHttpActionResult
      {
          public string Message { get; private set; }        
          public HttpStatusCode StatusCode { get; private set; }
      
          public NiceInternalServerExceptionResponse(
              string message, 
              HttpStatusCode code)
          {
              Message = message;
              StatusCode = code; 
          }
      
          public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
          {
              var response = new HttpResponseMessage(StatusCode);
              response.Content = new StringContent(Message);
              return Task.FromResult(response);
          }
      }
      

      在你的GlobalExceptionHandler 中传递HttpStatusCode.InternalServerError (500):

      public override void Handle(ExceptionHandlerContext context)
      {
          context.Result = new NiceInternalServerExceptionResponse(
              "The current operation could not be completed sucessfully.",
              HttpStatusCode.InternalServerError);
      }
      

      【讨论】:

      • 我已经实现了 Nice..class 并做到了: var response = new HttpResponseMessage();我只是没有通过状态码 ;-) 谢谢,它成功了!
      • @Elisabeth 哦,太棒了。如果此答案回答了您的问题,请考虑将其标记为已接受:)
      • 顺便说一句。我很困惑,你的最后一段是什么意思:“我无法辨别......”?我应该改变一些东西还是你看到不好的东西?我的意思是当状态码 500 返回到我的 html 客户端时,它会显示一个带有已记录异常 ID 的一般错误对话框。当返回 204 /200 时,当然不会显示此对话框。我希望现在更清楚?
      • @Elisabeth 我意思是我不明白问题的那一部分,但没关系 - 我从答案中删除了那部分。我很好奇为什么这被否决了......?
      猜你喜欢
      • 2021-10-23
      • 2021-12-18
      • 2013-02-15
      • 2018-04-27
      • 2018-12-26
      • 1970-01-01
      • 2019-12-28
      • 2013-12-04
      • 1970-01-01
      相关资源
      最近更新 更多