首页 > 解决方案 > 确保特定异常始终导致给定的 HTTP 响应状态代码

问题描述

要求

我有一个 ASP.Net MVC 应用程序,它可以与许多不同的库一起使用。与大多数库一样,各种函数调用可能会引发许多不同的异常之一。

目前,无论何时抛出任何异常,MVC 应用程序都会“处理”它们并将“内部服务器错误”(代码 500)返回给客户端(例如 Web 浏览器)。

这在大多数情况下都很好,但是,有一种特定的异常类型(在这种情况下UnauthorizedAccessException)我希望在响应中发送“未经授权”(代码 401)状态,而不是通常的 500 错误。

当前尝试

我做了一些研究,看起来“捕获”所有异常并处理它们的方法是使用该Application_Error方法。Application_Error所以我在课堂上尝试了以下实现MvcApplication

protected void Application_Error(object sender, EventArgs e)
{
    Exception ex = Server.GetLastError();

    if(ex is UnauthorizedAccessException)
    {
        Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
    }
}

问题

这里的问题是,虽然我可以调试并看到Response.StatusCode设置为 401,但客户端/浏览器仍然收到 500 错误。

我希望发生这种情况有一个很好的理由,但是我已经用尽了我的大脑来思考搜索词,这将为我提供我需要的答案。

问题

简而言之,我需要做什么才能获得我正在寻找的行为?


有关其他信息,最终我想要的是UnauthorizedAccessException具有与 MVC 如何处理未经身份验证的请求(重定向到登录页面)相同的行为。但是,我还需要它来处理 AJAX 请求,因为我的 javascript 可以检查401错误并执行一些特定的逻辑(在这种情况下,重定向到登录页面的响应不可行)

标签: c#asp.net-mvcexception-handlinghttpresponse

解决方案


一个聪明的方法是创建一个基本控制器,你的控制器继承默认控制器。在那里,您继承了默认的 Controller 类并覆盖了 OnException 方法。

public abstract class BaseController : Controller
{
    protected override void OnException(System.Web.Mvc.ExceptionContext filterContext)
    {
        var responseCode = Response.StatusCode;
        var exception = filterContext.Exception;
        switch (exception.GetType().ToString())
        {
            case "UnauthorizedAccessException":
                responseCode = 401;
                filterContext.ExceptionHandled = true;
                break;
        }

        Response.StatusCode = responseCode;

        base.OnException(filterContext);
    }
}

使它起作用的技巧是,filterContext.ExceptionHandled = true;如果您不将其设置为 true,服务器将返回 500。

您的控制器将继承BaseController;

public class UserController : BaseController
{
    public ActionResult Index(){
        return View();
    }
}

您需要添加到此代码中的是重定向到登录页面,重定向到您的OnException方法(如果需要)。我会为你做,但我没有足够的时间为你编写和测试它..目前正在等待自动化测试完成.. :-)

编辑:

我没有意识到您的视图也会引发错误,这显然不会由控制器处理。

在这种情况下,我们可以恢复到 Global.asax 上的原始 Application_Error 方法。

我们需要的是两行代码..

Response.StatusCode = 401;
Response.End();

第一行设置状态码为 401,第二行此时结束执行并触发 EndRequest 事件,因此 StatusCode 不会被修改为 500。

如果您想在回复中附加一条消息:

Response.Write("Oops, you're not authorized...");

Response.Clear();在开始修改错误处理程序中的响应对象之前调用是个好主意。


推荐阅读