Как управлять запросом перенаправления после вызова jQuery Ajax

Я использую $.post() для вызова сервлета с помощью Ajax, а затем использую полученный HTML-фрагмент для замены элемента div на текущей странице пользователя. Однако если сессия завершается, сервер посылает директиву перенаправления, чтобы отправить пользователя на страницу входа в систему. В этом случае jQuery заменяет элемент div содержимым страницы входа, заставляя глаза пользователя наблюдать редкую сцену.

Как я могу управлять директивой перенаправления из Ajax вызова с помощью jQuery 1.2.6?

Комментарии к вопросу (5)

Я читал этот вопрос и реализован подход, который уже заявил о настройке ответ код состояния HTTP до 278 для того, чтобы избежать браузер автоматически обрабатывает редиректы. Хотя это работает, я был немного недоволен, так как это немного взломать.

После более копать вокруг, я бросила этот подход и использован JSON с. В данном случае, все ответы на AJAX-запросы есть код состояния 200, а тело ответа содержит JSON-объект, который создается на сервере. В JavaScript на клиенте, то можно использовать объект JSON, чтобы решить, что он должен делать.

У меня была похожая проблема на вашу. Я выполнить AJAX-запрос, который имеет 2 возможных ответа: один, что редиректы браузер на новую страницу и один, что заменяет существующий HTML-форму на текущую страницу новой. Код jQuery, чтобы сделать это выглядит примерно так:

$.ajax({
    type: "POST",
    url: reqUrl,
    data: reqBody,
    dataType: "json",
    success: function(data, textStatus) {
        if (data.redirect) {
            // data.redirect contains the string URL to redirect to
            window.location.href = data.redirect;
        } else {
            // data.form contains the HTML for the replacement form
            $("#myform").replaceWith(data.form);
        }
    }
});

Объект JSON, что "данные" и построен на сервере иметь 2 членов: сведения.перенаправление " и " сведения.форма. Я нашел этот подход значительно лучше.

Комментарии (12)

Я решил эту проблему следующим образом:

  1. Добавление пользовательского заголовка в ответ:

индекс общественного ActionResult(){ если (!Свойство HttpContext.Пользователей.Идентичности.Метод isauthenticated) { Свойство HttpContext.Ответ.AddHeader("и REQUIRES_AUTH-то", то"1" - а); } обратный вид(); }

  1. Обязательные функции JavaScript на ajaxSuccess события и проверять, если заголовок существует:

$(документ).ajaxSuccess(функция(событие, запрос, параметры) { если (запрос.getResponseHeader('REQUIRES_AUTH') === '1') { окна.расположение = '/'; } });

Комментарии (10)

Нет браузеры правильно обрабатывают 301 и 302 ответы. А по факту уровень даже говорит, что они должны справиться с ними на "прозрачно" и которая является большой головной болью для производителей библиотеки AJAX. В РА-Аякс мы вынуждены были в через статус ответа HTTP-код 278 (просто какая-то "неиспользованные" и успех код) для обработки прозрачно перенаправляет с сервера...

Это действительно раздражает меня, и если кого-то здесь есть какая-то "тянет" в W3C и я был бы признателен, что вы могли бы дать консорциума W3C знаю, что мы действительно должны обращаться 301 и 302 коды сами...! ;)

Комментарии (4)
Решение

Решение, которое было в конечном итоге реализовано было использовать оболочку для функции обратного вызова AJAX-вызов, и в этот фантик проверять наличие определенного элемента на HTML-код, возвращенный кусок. Если элемент был найден, то обертка выполняется перенаправление. Если нет, фантик направил призыв к фактической функции обратного вызова.

Например, наша функция фантик был что-то вроде:

function cbWrapper(data, funct){
    if($("#myForm", data).length > 0)
        top.location.href="login.htm";//redirection
    else
        funct(data);
}

Затем, когда делает AJAX-вызов, мы использовали что-то вроде:

$.post("myAjaxHandler", 
       {
        param1: foo,
        param2: bar
       },
       function(data){
           cbWrapper(data, myActualCB);
       }, 
       "html"
);

Он работал на нас, потому что все AJAX всегда вызывает возвращенный HTML-код внутри элемента div, который мы используем для замены части страницы. Кроме того, нам нужно было только перенаправить на страницу входа.

Комментарии (3)

Мне нравится Timmerz'ы способ с небольшой долькой лимона. Если вы когда-нибудь вернулся значение contentType от текст/HTML когда вы'вновь ждет в JSON, вы, скорее всего, перенаправляется. В моем случае, я просто перезагрузите страницу, и он перенаправляется на страницу входа. Да, и проверить, что статус jqXHR составляет 200, который, кажется, глупо, потому что вы находитесь в функции ошибки, верно? В противном случае, законных случаях ошибка заставит итерационный перезагрузить (упс)

$.ajax(
   error:  function (jqXHR, timeout, message) {
    var contentType = jqXHR.getResponseHeader("Content-Type");
    if (jqXHR.status === 200 && contentType.toLowerCase().indexOf("text/html") >= 0) {
        // assume that our login has expired - reload our current page
        window.location.reload();
    }

});
Комментарии (2)

Используйте низкоуровневый вызов $.ajax():

$.ajax({
  url: "/yourservlet",
  data: { },
  complete: function(xmlHttp) {
    // xmlHttp is a XMLHttpRquest object
    alert(xmlHttp.status);
  }
});

Попробуйте это для редиректа:

if (xmlHttp.code != 200) {
  top.location.href = '/some/other/page';
}
Комментарии (9)

Я просто хотел поделиться своим подходом, так как это может это может помочь кому-то:

Я в принципе включен модуль JavaScript, которая обрабатывает материал проверки подлинности, как отображение имени пользователя, а также этом случае обращение перенаправление на страницу входа.

Мой сценарий: у нас в основном есть сервер ISA между которыми выслушивает все просьбы и отвечает кодом 302 и заголовок Location на страницу входа в систему.

В моем JavaScript-модуля мой подход было что-то вроде

$(document).ajaxComplete(function(e, xhr, settings){
    if(xhr.status === 302){
        //check for location header and redirect...
    }
});

Проблема (как многие здесь уже упоминали), что браузер обрабатывает редирект сам по себе, а потому мой ajaxCompleteобратного вызова никогда не называли, но вместо этого я получил **ответ уже перенаправлены страницу входа**, который, очевидно, был статус 200. Проблема: как вы определяете успешность 200 ответ ваша страница логин или просто некоторые другие произвольные страницы??

Решение ## в Поскольку я не смог запечатлеть 302 редирект ответы, я добавил заголовок LoginPage на моей странице логин, который содержал url самой страницы входа. В модуле я сейчас слушаю для заголовка и сделать редирект:

if(xhr.status === 200){
    var loginPageRedirectHeader = xhr.getResponseHeader("LoginPage");
    if(loginPageRedirectHeader && loginPageRedirectHeader !== ""){
        window.location.replace(loginPageRedirectHeader);
    }
}

...и это работает как шарм :). Вы можете спросить, почему я включать URL в LoginPage заголовок...ну в основном потому что я не нашел способа определить URL-адрес "получить" в результате автоматической переадресации расположение от `используем XHR-объект...

Комментарии (3)

Я знаю, что эта тема старая, но я'll даем еще один подход Я'вэ нашел и описанных ранее здесь. В принципе я'м с использованием ASP.MVC с помощью WIF (но это не очень важно в контексте данной темы - ответ будет адекватным независимо от того, какой используется основа. Ключ остается неизменной - решение вопросов, связанных с ошибками проверки подлинности при выполнении AJAX-запросов).

Подход, представленный ниже, может быть применено для всех AJAX-запросы из коробки (если они не переопределить событие beforeSend очевидно).

$.ajaxSetup({
    beforeSend: checkPulse,
    error: function (XMLHttpRequest, textStatus, errorThrown) {
        document.open();
        document.write(XMLHttpRequest.responseText);
        document.close();
    }
});

Перед любой AJAX-запрос выполняется методом CheckPulse `вызывается (метод контроллера, который может быть ничего простого):

[Authorize]
public virtual void CheckPulse() {}

Если пользователь не прошел проверку подлинности (маркер истек) такой способ невозможен (защита авторизации атрибут). Поскольку в рамках проверки подлинности, в то время как маркер истекает, он ставит состояния HTTP 302 в ответ. Если вы Don'т хотите, чтобы ваш браузер, чтобы обработать ответ 302 прозрачно, поймать его в глобальный.asax и изменение статуса ответа - например до 200 ОК. Кроме того, добавление заголовка, который указывает вам процесс такой ответ особым образом (позже на стороне клиента):

protected void Application_EndRequest()
{
    if (Context.Response.StatusCode == 302
        && (new HttpContextWrapper(Context)).Request.IsAjaxRequest())
    {                
        Context.Response.StatusCode = 200;
        Context.Response.AddHeader("REQUIRES_AUTH", "1");
    }
}

Наконец, на стороне клиента проверить такой пользовательский заголовок. Если представить - полное перенаправление на страницу входа в систему должно быть сделано (в окне моем случае`.местоположение заменяется URL из запроса, который обрабатывается автоматически в моих рамках).

function checkPulse(XMLHttpRequest) {
    var location = window.location.href;
    $.ajax({
        url: "/Controller/CheckPulse",
        type: 'GET',
        async: false,
        beforeSend: null,
        success:
            function (result, textStatus, xhr) {
                if (xhr.getResponseHeader('REQUIRES_AUTH') === '1') {
                    XMLHttpRequest.abort(); // terminate further ajax execution
                    window.location = location;
                }
            }
    });
}
Комментарии (3)

Я решил эту проблему так:

Добавить промежуточное ПО для обработки ответа, если это перенаправление для ajax-запроса, изменить ответ на нормальный ответ с URL-адреса перенаправления.

class AjaxRedirect(object):
  def process_response(self, request, response):
    if request.is_ajax():
      if type(response) == HttpResponseRedirect:
        r = HttpResponse(json.dumps({'redirect': response['Location']}))
        return r
    return response

Затем в ajaxComplete, если ответ содержит редирект, он должен быть редирект, так что смени браузер'ы местонахождение.

$('body').ajaxComplete(function (e, xhr, settings) {
   if (xhr.status == 200) {
       var redirect = null;
       try {
           redirect = $.parseJSON(xhr.responseText).redirect;
           if (redirect) {
               window.location.href = redirect.replace(/\?.*$/, "?next=" + window.location.pathname);
           }
       } catch (e) {
           return;
       }
   }
}
Комментарии (0)

Я думаю лучший способ это исправить-это использовать существующий протокол HTTP-коды ответов, а конкретно 401 несанкционированного.

Вот как я ее решал:

  1. На стороне сервера: если сессия истекает, и запрос является AJAX. отправляет ответ 401 код заголовка
  2. На стороне клиента: привязать к событиям Аякс

$('тело').персонализация('ajaxSuccess',функция(событие,запрос,параметры){ если (401 == запросу.статус){ окна.расположение = '/пользователи/логин'; } }).персонализация('ajaxError',функция(событие,запрос,параметры){ если (401 == запросу.статус){ окна.расположение = '/пользователи/логин'; } });

ИМО это более универсальный и вы не пишете новые заголовка пользовательских спецификаций/. Вы также не должны изменять любой из ваших существующих AJAX-вызовы.

Редактировать: в @Роб'с комментарием ниже, 401 (код состояния HTTP для ошибки проверки подлинности) должен быть индикатор. См https://stackoverflow.com/questions/3297048/403-forbidden-vs-401-unauthorized-http-responses для более подробной информации. С этим, как говорится в некоторых фреймворков использовать 403 для обоих и ошибки авторизации аутентификации - ну и соответственно адаптироваться. Спасибо Роб.

Комментарии (1)

Большинство предлагаемых решений использовать обходной путь, используя дополнительную заголовка или кода несоответствующем протоколу HTTP. Эти решения, скорее всего, работает, но немного 'богатство'. Я'вэ придумать другое решение.

Мы'вновь с помощью WIF, который настроен на редирект (passiveRedirectEnabled=на"Правда") смотрите на ответ 401. Перенаправление полезно при обращении с нормальными запросами, но выиграл't работа для ajax-запросов (поскольку браузеры выиграл'т выполнять 302/редирект).

Используя следующий код в глобальный.эйсакс можно отключить редирект для запросов AJAX:

    void WSFederationAuthenticationModule_AuthorizationFailed(object sender, AuthorizationFailedEventArgs e)
    {
        string requestedWithHeader = HttpContext.Current.Request.Headers["X-Requested-With"];

        if (!string.IsNullOrEmpty(requestedWithHeader) && requestedWithHeader.Equals("XMLHttpRequest", StringComparison.OrdinalIgnoreCase))
        {
            e.RedirectToIdentityProvider = false;
        }
    }

Это позволяет вернуть 401 ответы на AJAX-запросы, что ваш JavaScript, может обработать по перезагрузки страницы. Перезагрузки страницы будут бросать 401, который будет заниматься жена (и WIF будет перенаправлять пользователя на страницу входа).

Пример JavaScript-кода для обработки ошибки 401:

$(document).ajaxError(function (event, jqxhr, settings, exception) {

    if (jqxhr.status == 401) { //Forbidden, go to login
        //Use a reload, WIF will redirect to Login
        location.reload(true);
    }
});
Комментарии (1)

Эта проблема может появиться тогда, используя метод ASP.NET RedirectToAction в MVC. Чтобы предотвратить форма отображения ответ на div, вы можете просто сделать какой-то фильтр AJAX ответ на входящие ответы $.метода ajaxsetup. Если ответ содержит перенаправление MVC, вы можете оценить это выражение на JS стороне. Пример кода ниже ДШ:

$.ajaxSetup({
    dataFilter: function (data, type) {
        if (data && typeof data == "string") {
            if (data.indexOf('window.location') > -1) {
                eval(data);
            }
        }
        return data;
    }
});

Если данные: "в окно.расположение = '/аккаунт/логин' и" выше фильтра будет поймать и оценить, чтобы сделать перенаправления вместо того, чтобы данные, которые будут отображаться.

Комментарии (1)

Другое решение я нашел (особенно полезно, если вы хотите установить глобальный поведения) заключается в использовании $.метода ajaxsetup() метод вместе с собственностью состояния. Как и другие отметили, Дон'т использовать редирект состояния (3 * х), вместо того, чтобы использовать 4хх statusCode и обрабатывать перенаправления на стороне клиента.

$.ajaxSetup({ 
  statusCode : {
    400 : function () {
      window.location = "/";
    }
  }
});

Заменить 400 С состояния, которое вы хотите обработать. Как уже писали 401 не санкционировано может быть хорошей идеей. Я использую 400, так как она'Очень неспецифические и я могу использовать 401 для более конкретных случаях (например, неправильные учетные данные для входа в систему). Поэтому вместо того, чтобы перенаправлять непосредственно ваш сервер должен возвращать ошибку-код 4хх, когда время сессии истекло и вы обрабатывать перенаправления на стороне клиента. Работает идеально подходит для меня даже с фреймворками типа backbone.js

Комментарии (2)

Собираю то, что Владимир Прудников и Томас Хансен сказал:

  • Измените ваш код на стороне сервера, чтобы обнаружить, если это'ы то XHR. Если это так, установить код ответа перенаправление 278. В Django:

если запрос.is_ajax(): В ответ.status_code = 278

Это делает браузер обработать ответ, как успех, и передать его в ваш JavaScript.

  • В ваших JS, убедитесь, что Отправка форм через AJAX, проверяем код ответа и перенаправление, если необходимо:

$(' мой-форма').подать(функция(событие){

событие.метод preventDefault(); ВАР вариантов = { URL-адрес: $(Этот).М('действий'), тип: 'пост', полная: функция(ответ, textStatus) { если (ответ.статус == 278) { В окне.расположение = ответ.getResponseHeader('местоположение') } еще { ... ваш код ... } }, данные: $(этот).сериализовать(), }; и GT; $.Аякс(варианты); });

Комментарии (0)

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

$(document).ready(function ()
{
    $(document).ajaxSend(
    function(event,request,settings)
    {
        var intercepted_success = settings.success;
        settings.success = function( a, b, c ) 
        {  
            if( request.responseText.indexOf( "" ) > -1 )
                window.location = window.location;
            else
                intercepted_success( a, b, c );
        };
    });
});

Я проверяю наличие HTML-тег, но вы можете изменить метод indexOf, чтобы найти все уникальные строки существует в Вашей странице входа в систему...

Комментарии (1)

Попробовать

    $(document).ready(function () {
        if ($("#site").length > 0) {
            window.location = "" + "Login/LogOn";
        }
    });

Положите его на страницу входа. Если она была загружена в div на главной странице, он будет перенаправлять до страницы входа. на " площадку" это идентификатор элемента div, который расположен на всех страницах, кроме страницы входа.

Комментарии (0)
    <script>
    function showValues() {
        var str = $("form").serialize();
        $.post('loginUser.html', 
        str,
        function(responseText, responseStatus, responseXML){
            if(responseStatus=="success"){
                window.location= "adminIndex.html";
            }
        });     
    }
</script>
Комментарии (0)

А ответов, кажется, работает для людей, если вы'вновь с использованием Spring безопасности я нашел расширение LoginUrlAuthenticationEntryPoint и добавления специального кода для обработки Аякс более надежной. Большинство примеров перехвата все редиректы не только ошибки проверки подлинности. Это было нежелательно для проекта, Я работаю на. Вы можете найти необходимость продлить ExceptionTranslationFilter и переопределить в "sendStartAuthentication и" метод, чтобы удалить шаг кэширование если вы Don'т хотим, не AJAX-запрос кэшируется.

Пример AjaxAwareAuthenticationEntryPoint:

public class AjaxAwareAuthenticationEntryPoint extends
    LoginUrlAuthenticationEntryPoint {

    public AjaxAwareAuthenticationEntryPoint(String loginUrl) {
        super(loginUrl);
    }

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        if (isAjax(request)) {
            response.sendError(HttpStatus.UNAUTHORIZED.value(), "Please re-authenticate yourself");
        } else {
        super.commence(request, response, authException);
        }
    }

    public static boolean isAjax(HttpServletRequest request) {
        return request != null && "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
    }
}

Источники: 1, 2

Комментарии (4)

Я решил эту проблему, поставив следующие в мою страницу login.php .

<script type="text/javascript">
    if (top.location.href.indexOf('login.php') == -1) {
        top.location.href = '/login.php';
    }
</script>
Комментарии (0)

Позвольте мне еще раз процитировать проблемы, как описал @стег

У меня была похожая проблема на вашу. Я выполнить AJAX-запрос, который имеет 2 возможные ответы: один, который перенаправляет браузер на новую страницу и тот, который заменяет существующий HTML-форм на текущей странице нового один.

ИМХО это реальная проблема, и должны быть официально продлен на текущий стандартами http.

Я считаю, что новый стандарт HTTP будет использовать новый статус-код. смысл: в настоящее время 301/302 сообщает браузеру, что нужно пойти и забрать содержимое это запрос на место новый.

В расширенном стандарте, он скажет, что если статус ответа: 308 (просто пример), то браузер редирект главной страницы на "местоположение" указана.

Это, как говорится; Я'м уже склонен подражать это будущее поведение, и поэтому, когда документ.редирект нужен, у меня есть сервер ответить, как:

status: 204 No Content
x-status: 308 Document Redirect
x-location: /login.html

Когда Яш получает в "статус: 204", он проверяет наличие х-статуса: 308` заголовок, а не документ.перенаправление на страницу указана в заголовке "местоположение".

Это делает никакого смысла для вас?

Комментарии (0)