Пользовательская обработка исключений во время AJAX-запроса вызывает HttpException - PullRequest
0 голосов
/ 29 июня 2018

Когда мое приложение встречает исключение типа UnauthorizedAccessException во время запроса AJAX, я хочу обработать поведение самостоятельно и вернуть пользовательский ответ 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-адрес строки, логический конец-ответ, логический перманент) в 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, логическое и завершено синхронно)

Я получаю эту информацию об исключении при добавлении точки останова к методу Application_Error MvcApplication, например:

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

Итак, хотя мое приложение дает результат именно так, как я хочу с точки зрения пользовательского опыта. У меня есть это «закулисное» исключение, которого я действительно не хочу, чтобы это произошло.

Что здесь не так? И что я могу сделать, чтобы исключение не произошло?

Ответы [ 2 ]

0 голосов
/ 29 июня 2018

Мой другой ответ был неверным, я только что проверил его.

Решение проблемы немного отличается от предыдущего решения, которое я вам дал. Ваше промежуточное программное обеспечение является причиной проблемы.

Я подозреваю, что вы используете то, что я использую; 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 по умолчанию ..: -)

0 голосов
/ 29 июня 2018

Продолжая комментарии, я решил, что лучше всего опубликовать его как ответ из-за ограничения по количеству символов. Это частично ответ, потому что у меня нет подходящего проекта для тестирования.

Когда я сказал в комментарии, что не могу реплицироваться, это произошло потому, что я запустил те тесты в проекте, над которым я работаю - WebApi2, и у меня не будет такого поведения.

Если мое мнение правильно мне подходит, ваша проблема заключается в том, что вы внедряете API-подобную функциональность в проект MVC и, конечно, вы видите ожидаемое поведение.

Когда вы получаете 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();
}

Если это не работает; Ваше промежуточное программное обеспечение для аутентификации может также отвечать за настройку этого перенаправления, и это, к сожалению, будет установлено в другом месте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...