【问题标题】:Ensure that a specific exception always results in a given HTTP response status code确保特定异常始终导致给定的 HTTP 响应状态代码
【发布时间】:2018-06-28 14:54:01
【问题描述】:

要求

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

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

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

当前尝试

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

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-mvc exception-handling httpresponse


    【解决方案1】:

    一个聪明的方法是创建一个基本控制器,你的控制器继承默认控制器。在那里你继承默认的 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(); 是个好主意。

    【讨论】:

    • 方便,我已经有一个我正在使用的基本控制器。进行了一些更改以以不同的方式处理 ajax 请求,进行了一些测试,一切似乎都按预期工作。感谢您的时间和回答!
    • 其实这并没有捕捉到all异常。如果从视图页面抛出异常,那么它会绕过这个方法,只去Application_Error。我目前正在寻找解决方案,但是如果您能想到任何想法,将不胜感激?它特别来自 _Layout 视图
    • @musefan 当然,我没有意识到你会在视图中抛出错误。试试我的编辑。
    • 猜对了。因为我可以确定 AJAX 请求将在 OnException 中捕获(因为您不能从视图渲染中进行 AJAX),所以我在 Application_Error 中需要的只是检查异常类型,然后执行 HttpContext.Current.Response.Redirect("some url"); 来处理非ajax 错误在视图中。我所有的测试用例现在似乎都通过了:)
    • 如果您碰巧知道解决方案,可能是a chance for some extra rep
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-11
    • 2018-01-21
    • 1970-01-01
    • 2013-06-15
    相关资源
    最近更新 更多