Форма, которая делает браузер перенаправленным, когда к нему обращается обычная форма отправки или запрос Ajax - это возможно? - PullRequest
4 голосов
/ 23 сентября 2009

У меня есть веб-страница с формой. Когда пользователь отправляет форму, я хочу, чтобы сервер перенаправил браузер на страницу, отличную от действия формы. Сейчас я делаю это с помощью PHP-функции header для отправки кода состояния 302. Работает нормально.

Я пытаюсь заставить страницу на сервере перенаправлять браузер одинаково, независимо от того, была ли она отправлена ​​нормально (без Javascript) или через Ajax. Я попытался сделать это, установив местоположение окна на любой URL в заголовке Location. Я использую JQuery, и делаю вызов, как это:

$.ajax({
    url: this.action,
    type: "POST",
    data: getFormData(this),
    complete: function(request) {
        window.location.assign(request.getResponseHeader("Location"));
    }
});

Однако это не сработало. Подумав об этом, я понял, что это не очень удивительно. В Ajax-запросе браузер должен прозрачно обрабатывать ответы перенаправления, такие как коды 302, перед изменением readyState. Когда выполняется полная функция, она ищет заголовок Location в конечном пункте назначения и не находит его.

В качестве эксперимента я попытался отправить код состояния 200 с заголовком Location. Я попробовал запрос Ajax, и он работал нормально. Однако, когда я подал заявку без Ajax, это не сработало. Браузер перешел на страницу действия формы и остался там, как будто игнорировал заголовок Location.

Можно ли как-то перенаправить одну и ту же страницу в обоих случаях, при этом серверу не нужно знать или заботиться о том, является ли запрос Ajax-запросом?

В случае, если это имеет значение, я пробовал форму в различных браузерах (IE8, IE7, IE6, Firefox 3.5, Chrome) с одинаковыми результатами каждый раз. Кроме того, я выполняю запрос на публикацию, чтобы избежать столкновения с 2083-символьным ограничением длины URL в IE.

Ответы [ 8 ]

5 голосов
/ 23 сентября 2009

HTTP 302-ответ молча используется XmlHttpRequest реализациями (например, функция jQuery ajax). Это особенность.

Способ, который я решил в прошлом, состоит в том, чтобы обнаружить запросы XmlHttpRequest и выдать заголовок "Content-Location" (вместо заголовка "Location"). Наиболее кросс-библиотечный способ сделать это - проверить заголовок "X-Requested-With" http в вашем коде на стороне сервера (jQuery, Prototype, Mootools, среди прочего, устанавливают это):

if (@$_SERVER['HTTP_X_REQUESTED_WITH']  == 'XMLHttpRequest') {
    header('Content-Location: ' . $redirect_url);
} else {
    header('Location: ' . $redirect_url);
}

Вам по-прежнему необходимо указать специальный код на стороне клиента:

$.ajax({
    // ...
    complete: function(xhr) {
        var redirect_url = xhr.getResponseHeader("Content-Location");
        if (redirect_url) {
            window.location = redirect_url;
        }
    }
})
0 голосов
/ 23 сентября 2009

Вот еще один вариант, хотя вам нужно будет провести несколько кросс-браузерных тестов:

complete: function(request) {
    if(request.status == 200) {
        var doc = document.open(request.getResponseHeader('Content-Type'));
        doc.write(request.responseText);
        doc.close();
    }
}

Основные недостатки: URL в адресной строке не меняется; может связываться с кнопкой назад / историей

Хотя я думаю, что идея @ crescentfresh - это путь

0 голосов
/ 23 сентября 2009

Почему бы вашему "действию ajax" просто заполнить необходимые поля формы и вместо этого отправить форму? Таким образом, вы получите точно такое же поведение, что и при отправке вручную.

0 голосов
/ 23 сентября 2009

Вы пытались использовать функцию ошибки вместо завершения?

$.ajax({
    url: this.action,
    type: "POST",
    data: getFormData(this),
    error: function(request) {
        if(request.status == 302)
            window.location.assign(request.getResponseHeader("Location"));
    }
});

jQuery отправляет любой ответ 3xx функции ошибки. Возможно, заголовок «Местоположение» все еще будет доступен на этом этапе.

0 голосов
/ 23 сентября 2009

«завершит» работу:

$.ajax({
    type: frm.attr('method'),
    url: frm.attr('action'),
    data: frm.serialize(),
    complete: complete(xhr, status) {
       window.location.assign(xhr.getResponseHeader("Location"));

    }
});
0 голосов
/ 23 сентября 2009

Передайте дополнительный параметр в ваш запрос ajax для простого определения типа запроса. Когда ajax - не перенаправлять - просто отправьте целевой URL, затем перенаправьте клиентскую сторону в обратном вызове ajax через location.href

как это:

$.post('/controller/action', {formdata}, function (redirect_to) {
    location.href = redirect_to;
});
0 голосов
/ 23 сентября 2009

Я хотел бы узнать больше о вашем сценарии использования для этого. Насколько я понимаю, вы пытаетесь заставить ваше приложение загрузить страницу, основанную на заголовке 'Location' вызова Ajax внутри него? Я бы спросил, почему?

HTTP-заголовок не не кажется правильным местом для получения этой информации. Разве ваше приложение по сути не делает запрос, который говорит: «Куда мне перенаправить?». Нет никакой причины, по которой ответ Ajax должен отвечать 302 и заголовком «Location». Почему бы просто не ответить ему JSON или XML, который содержит новый URL?

Редактировать: просто перечитайте свой предпоследний абзац. Я не уверен, что есть хороший способ достичь того, что вы хотите. Концепция звучит для меня сломанной. :)

0 голосов
/ 23 сентября 2009

Если пользователь перенаправляется независимо от того, почему Ajax? Смысл Ajax в этом заключается в том, чтобы вносить изменения в страницу без обновления страницы, поэтому используемая вами техника выглядит как создание принтера, который выводит в загрузочный лоток.

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