Как управлять запросом на перенаправление после вызова jQuery Ajax - PullRequest
1276 голосов
/ 14 октября 2008

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

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

Ответы [ 31 ]

18 голосов
/ 02 мая 2014

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

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

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

18 голосов
/ 14 февраля 2014

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

Мы используем WIF, который настроен на перенаправление (passiveRedirectEnabled = "true") на ответ 401. Перенаправление полезно при обработке обычных запросов, но не будет работать для запросов AJAX (поскольку браузеры не будут выполнять перенаправление 302 /).

Используя следующий код в вашем global.asax, вы можете отключить перенаправление для запросов 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 (и 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);
    }
});
17 голосов
/ 27 октября 2016

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

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

Если данные равны: "window.location = '/ Acount / Login'" выше фильтра поймает это и оценит перенаправление вместо того, чтобы позволить отображению данных.

16 голосов
/ 07 августа 2009

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

  • Измените свой код на стороне сервера, чтобы определить, является ли он XHR. Если это так, установите код ответа для перенаправления на 278. В джанго:
   if request.is_ajax():
      response.status_code = 278

Это заставляет браузер воспринимать ответ как успешный и передает его в Javascript.

  • В вашем JS убедитесь, что отправка формы осуществляется через Ajax, проверьте код ответа и, при необходимости, перенаправьте:
$('#my-form').submit(function(event){ 

  event.preventDefault();   
  var options = {
    url: $(this).attr('action'),
    type: 'POST',
    complete: function(response, textStatus) {    
      if (response.status == 278) { 
        window.location = response.getResponseHeader('Location')
      }
      else { ... your code here ... } 
    },
    data: $(this).serialize(),   
  };   
  $.ajax(options); 
});
16 голосов
/ 17 августа 2010

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

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

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

12 голосов
/ 10 сентября 2011
    <script>
    function showValues() {
        var str = $("form").serialize();
        $.post('loginUser.html', 
        str,
        function(responseText, responseStatus, responseXML){
            if(responseStatus=="success"){
                window.location= "adminIndex.html";
            }
        });     
    }
</script>
12 голосов
/ 05 октября 2010

Попробуйте

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

Поместите это на страницу входа. Если он был загружен в div на главной странице, он будет перенаправлен на страницу входа. «#site» - это идентификатор div, который находится на всех страницах, кроме страницы входа.

11 голосов
/ 17 сентября 2013

Хотя ответы, кажется, работают для людей, если вы используете Spring Security, я обнаружил, что расширение LoginUrlAuthenticationEntryPoint и добавление специального кода для обработки AJAX более надежны. Большинство примеров перехватывают all , перенаправляя не только ошибки аутентификации. Это было нежелательно для проекта, над которым я работаю. Может также возникнуть необходимость расширить ExceptionTranslationFilter и переопределить метод «sendStartAuthentication», чтобы удалить шаг кэширования, если вы не хотите, чтобы неудавшийся 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

11 голосов
/ 05 декабря 2011

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

<script type="text/javascript">
    if (top.location.href.indexOf('login.php') == -1) {
        top.location.href = '/login.php';
    }
</script>
9 голосов
/ 13 июля 2018

Позвольте мне еще раз процитировать проблему, описанную @ Steg

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

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

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

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

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

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

Когда JS получает "status: 204", он проверяет наличие заголовка x-status: 308 и выполняет document.redirect для страницы, указанной в заголовке location.

Имеет ли это какой-то смысл для вас?

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