API 异常过滤器在 ASP.NET MVC 中返回 200 异常响应代码

我为我的 API 编写了一个异常过滤器来处理 API 中抛出的异常:

using System;
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ApiExceptionFilter : ExceptionFilterAttribute {

    public override void OnException(ExceptionContext context) {

        // First, generate the status code based on the exception type
        HttpStatusCode status = context.Exception switch {
            UnauthorizedAccessException => HttpStatusCode.Unauthorized,
            ArgumentException => HttpStatusCode.BadRequest,
            MissingHeaderException => HttpStatusCode.BadRequest,
            NotFoundException => HttpStatusCode.NotFound,
            _ => HttpStatusCode.InternalServerError,
        };

        // Next, inject the status code and exception message into
        // a new error response and set the result with it
        context.Result = new JsonResult(new ErrorResponse {
            StatusCode = status,
            Message = context.Exception.Message
        });

        // Finally, call the base function
        base.OnException(context);
    }
}

此函数按预期拦截异常,但我遇到的问题是它总是返回一个 OK 响应。如何确保响应包含异常消息并且响应代码是非 200 值?

stack overflow API exception filter returns 200 response code on exception in ASP.NET MVC
原文答案
author avatar

接受的答案

而不是返回一个 JsonResult - 它不公开要设置的状态代码属性 - 返回一个 ExceptionResult 并像这样设置状态代码:

context.Result = new ExceptionResult(context.Exception, true)
{ StatusCode = status };

如果您仍想使用您的 ErrorResponse 对象,只需使用对象结果:

context.Result = new ObjectResult(new ErrorResponse {
    StatusCode = status,
    Message = context.Exception.Message
    })
    // set status code on result
    { StatusCode = status };

答案:

作者头像

在 .NET Core/.NET 6 上,我们没有 ExceptionResult,但我们仍然可以实现这个目标。我们可以为此请求手动设置 StatusCode。

    public override void OnException(ExceptionContext actionExecutedContext)
    {
        _logger.Error(actionExecutedContext.Exception);
        actionExecutedContext.ExceptionHandled = true;
        actionExecutedContext.HttpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
        actionExecutedContext.Result = new ObjectResult(new ErrorResponse()
        {
            StatusCode = (HttpStatusCode) StatusCodes.Status500InternalServerError,
            Message = actionExecutedContext.Exception.Message,
        });
        base.OnException(actionExecutedContext);
    }