【问题标题】:Custom handling of exceptions during AJAX request is causing a HttpExceptionAJAX 请求期间异常的自定义处理导致 HttpException
【发布时间】:2018-06-29 14:07:20
【问题描述】:

当我的应用程序在 AJAX 请求期间遇到 UnauthorizedAccessException 类型的异常时,我想自己处理该行为并返回自定义 JSON 响应。

所以我在基本控制器中重写了OnException 方法,我的所有控制器都继承自该方法,如下所示:

protected override void OnException(ExceptionContext filterContext)
{
    var exception = filterContext.Exception;

    if (exception is UnauthorizedAccessException)
    {
        filterContext.ExceptionHandled = true;

        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
            filterContext.HttpContext.Response.ContentType = "application/json";

            JavaScriptSerializer serializer = new JavaScriptSerializer();
            string json = serializer.Serialize(new { IsUnauthenticated = true });
            filterContext.HttpContext.Response.Write(json);

            filterContext.HttpContext.Response.End();
        }
        else
        {
            filterContext.Result = RedirectToAction("LogOut", "Account");
        }
    }
    else
    {
        // Allow the exception to be processed as normal.
        base.OnException(filterContext);
    }
}

现在这几乎完全符合我的要求。如果在 AJAX 请求期间发生异常,我的 JavaScript 将根据需要获取正确的 JSON 对象。

但是,问题是应用程序随后在内部遭受HttpException,并带有消息:

发送 HTTP 标头后无法重定向。

还有来自异常的堆栈跟踪:

在 System.Web.HttpResponse.Redirect(字符串 url,布尔值 endResponse,布尔值永久) 在 System.Web.Security.FormsAuthenticationModule.OnLeave(对象源,EventArgs eventArgs) 在 System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() 在 System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep 步骤) 在 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

当向MvcApplicationApplication_Error 方法添加断点时,我得到了这个异常信息,如下所示:

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

因此,尽管我的应用程序在用户体验方面完全符合我的要求。我真的不想发生这种“幕后”异常。

这里出了什么问题?我能做些什么来防止异常的发生?

【问题讨论】:

  • 您确定Application_Error 是个问题吗?如果您评论它,错误会消失吗?
  • 哦,我误会你了,对不起!你的Application_Error 很好。
  • 您能否澄清一下,当您的控制器抛出 UnauthorizedAccessException AND filterContext.HttpContext.Request.IsAjaxRequest()false 时,您会得到这个 HttpException
  • 对不起,musefan,我无法为 Ajax 请求和重定向进行复制。我总能得到想要的结果。您的错误字面意思是它所说的内容,因此您必须也在代码中的其他地方发送响应,或者您在错误处理程序的响应之后重定向。
  • @vasily.sib:它发生在 ISAjaxRequest 为真的代码之后。但是,我不知道是什么扔了它。 VS 中的调用堆栈在异常时为空。不过,我会在问题中添加异常堆栈跟踪......

标签: c# asp.net-mvc exception-handling


【解决方案1】:

从 cmets 继续,我认为由于字符限制,最好将其发布为答案。这部分是一个答案,因为我面前没有合适的项目来测试。

当我在评论中说我无法复制时,那是因为我在我正在从事的 WebApi2 项目中运行了这些测试,我不会有相同的行为。

如果我的想法正确,那么您的问题在于您正在 MVC 项目中实现类似 API 的功能,当然您看到的是预期的行为。

当您收到 UnauthorizedException 时,框架会尝试自动将您重定向到登录屏幕(或错误页面)。您需要禁用该行为(显然)。

您可以尝试使用以下方法在处理程序中抑制它:

filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
filterContext.HttpContext.Response.Redirect(null);

最终结果应该是这样的:

if (!filterContext.HttpContext.Request.IsAjaxRequest())
{
    filterContext.HttpContext.Response.StatusCode = 
    (int)System.Net.HttpStatusCode.Unauthorized;

    filterContext.HttpContext.Response.ContentType = "application/json";



    filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;

    JavaScriptSerializer serializer = new JavaScriptSerializer();
    string json = serializer.Serialize(new { IsUnauthenticated = true });
    filterContext.HttpContext.Response.Write(json);

    filterContext.HttpContext.Response.End();
}

如果这不起作用;您的身份验证中间件也可能负责设置此重定向,不幸的是,这将在其他地方设置。

【讨论】:

    【解决方案2】:

    我的另一个答案是错误的,我刚刚测试过。

    该问题的解决方案与我之前给您的解决方案略有不同。您的中间件是导致问题的原因。

    我怀疑你正在使用我正在使用的东西; Microsoft.ASPNET.Identity。

    在您的 Startup.cs 中,您需要添加 OnApplyRedirect 委托。

    你的代码应该和我的类似:

    app.UseCookieAuthentication(new CookieAuthenticationOptions
                {
                    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                    LoginPath = new PathString("/Account/Login"),
                    Provider = new CookieAuthenticationProvider
                    {
                        OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                            validateInterval: TimeSpan.FromMinutes(30),
                            regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)),
                         OnApplyRedirect = ctx =>
                         {
                             // add json response here...
                             ctx.RedirectUri = null;
    
                         }
                    }
                });
    

    从您的原始处理程序中,移动响应并将其添加到 ctx.Response...

    希望这能让它重回正轨。在 OnApplyRedirect 中,您可能需要检查它是否是 ajax 请求,然后禁用重定向,否则您将获得丑陋的 asp 默认错误页面。.. :-)

    【讨论】:

    • 感谢您的回答。我一直在寻找您的答案,而您的其他(已删除)答案对我有用。但只有SuppressFormsAuthenticationRedirect = true 部分,因为Redirect(null) 实际上会引发错误,因为您不能使用null 值。我不完全确定这个答案的作用,但我担心它会产生其他不良影响,并且作为另一个答案要简单得多,并且似乎可以完成我将继续使用的工作。如果您取消删除它,请告诉我,以便我可以相应地奖励它。再次感谢您花时间帮助我
    • @musefan 我已取消删除答案。我认为我的答案基于不同的场景,因为我对实际项目进行了一些测试,并且都显示了不同的结果。正如我之前所说,这完全取决于您的项目设置和中间件等。很高兴一种方法有效,我取消了正确的答案。
    猜你喜欢
    • 1970-01-01
    • 2013-09-20
    • 2021-08-31
    • 1970-01-01
    • 2012-05-15
    • 1970-01-01
    相关资源
    最近更新 更多