Как запретить запросам ajax следовать перенаправлениям с помощью jQuery

103

Я использую функции jQuery ajax для доступа к веб-сервису, но сервер вместо того, чтобы возвращать ответ с кодом состояния, описывающим проблему, запрос перенаправляется на страницу с заголовком 200, описывающим проблему. Я не могу вносить в это какие-либо изменения, поэтому мне нужно как-то решить эту проблему на клиенте.

Пример: запрос идет на какой-то URL, который не найден, поэтому я получаю 302 редирект в другое место. Отправляется новый запрос, и я получаю 200 OK, что предотвращает срабатывание обратного вызова ошибки.

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

Йорген
источник
Это может помочь: stackoverflow.com/questions/1804928/handle-jquery-ajax-redirect
PiTheNumber
8
Странно, что ваш бэкэнд сообщает 302, если не найдено, вместо 404.
Джейк Фител
Возможный дубликат запрета перенаправления Xmlhttprequest
пользователь

Ответы:

96

Мне ваш вопрос интересен, но проблема в целом кажется мне больше недоразумением. По крайней мере, я постараюсь объяснить свое понимание проблемы.

Тихое (прозрачное) перенаправление является частью XMLHttpRequestспецификации ( особенно см. Здесь слова «... прозрачно следовать перенаправлению ...»). В стандарте упоминается только то, что пользовательский агент (веб-браузер) может предотвращать или уведомлять об определенных видах автоматических перенаправлений, но это не является их частью XMLHttpRequest. Это часть конфигурации HTTP-клиента (конфигурации ОС) или конфигурации веб-браузера. Так что jQuery.ajaxне может быть никакого варианта, где вы можете предотвратить перенаправление.

Вы можете видеть, что перенаправление HTTP является частью протокола HTTP, а не частью XMLHttpRequest. Итак, это другой уровень абстракции или сетевой стек. Например, данные из XMLHttpRequestмогут быть получены из прокси-сервера HTTP или из локального кеша браузера, и это часть протокола HTTP. В основном сервер, который предоставляет данные, а не клиент, может влиять на кеширование.

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

XMLHttpRequestСтандарт говорит , что конфигурация клиента может иметь варианты , которые предотвращают переназначение. В случае с «миром Microsoft», который я лучше знаю, вы можете посмотреть функцию WinHttpSetOption, которую можно использовать для установки WINHTTP_OPTION_DISABLE_FEATUREопции со WINHTTP_DISABLE_REDIRECTSзначением. Другой способ - использование WINHTTP_OPTION_REDIRECT_POLICYопции со WINHTTP_OPTION_REDIRECT_POLICY_NEVERзначением. Еще одна функция, которую можно использовать в Windows, - это функция WinHttpSetStatusCallback, которая может установить функцию обратного вызова, получившую некоторые уведомления, например WINHTTP_CALLBACK_FLAG_REDIRECT.

Таким образом, возможно реализовать ваши требования в целом, но решение, вероятно, не будет независимым от операционной системы или веб-браузера и не будет на уровне jQuery.ajaxили XMLHttpRequest.

Олег
источник
2
Отличный ответ с отличным пониманием! У меня есть некоторый опыт работы с curl, для которого вы можете установить такие же флаги, как вы упомянули. Я надеялся, что такие инструкции можно будет передать браузеру, но из вашего ответа я понимаю, что ожидаемым поведением будет следование перенаправлениям, как если бы первоначальный запрос был отправлен в место, назначенное сервером.
Jørgen
@ Jørgen: Пожалуйста! В большинстве сценариев перенаправление вообще не проблема. Вы не описываете контекст, в котором вы используете jQuery.ajax, и имеете ли вы полный контроль над веб-сервером, на который вы отправляете запрос. Поэтому трудно дать вам другие советы, которые действительно могут решить вашу проблему.
Олег
Боюсь, я не контролирую серверную часть. Думаю, лучше всего мне проанализировать или проверить содержание ответа.
Jørgen
@ Jørgen: Почему в вашем случае проблема с перенаправлением? Если сервер временно или навсегда переместил какую-либо страницу в другое место, он может перенаправить ваш исходный запрос в новое место. Все будет нормально. Администратор может настроить веб-сервер для выполнения перенаправления, например, во время операции восстановления на сервере или любой другой поддержки. Если вы запросите сервер по URL-адресу, имеющему DNS, администратор может изменить сопоставление IP-адресов на другой сервер. Он может выполнять перенаправление HTTP так же, как реконфигурацию DNS. В чем дело?
Олег
Моя проблема в том, что перенаправление переходит на страницу общей ошибки. Я знаю, что сервер должен быть настроен по-другому, но пока мне нужно будет найти решение для этой ситуации как есть.
Jørgen
23

Я не верю, что это возможно. Базовая библиотека (XHR) делает новый запрос прозрачным. При этом то, что я сделал в этих ситуациях (обычно сделка с тайм-аутом сеанса, которая переводит меня на страницу входа), - это отправка настраиваемого заголовка ответа. У меня также есть глобальный обработчик ajax, который проверяет наличие этого заголовка и соответствующим образом реагирует, когда он присутствует (например, перенаправляя всю страницу на экран входа в систему).

Если вам интересно, вот код jQuery, который я должен следить за этим настраиваемым заголовком:

/* redirects main window when AJAX request indicates that the session has expired on the backend. */
function checkSession(event, xhr, ajaxOptions)
{
    if (xhr.readyState == 4)
    {
        if(xhr.getResponseHeader("Login-Screen") != null && xhr.getResponseHeader("Login-Screen").length)
        {
            window.location.href='sessionExpired.html'; //whatever
        }
    }
}

$(document).ajaxComplete(checkSession)
Джейк Физел
источник
1
Спасибо, думаю, мне придется согласиться на аналогичный подход, анализируя ответ.
Jørgen
11

Я нашел функцию, чтобы проверить, был ли ваш звонок перенаправлен. Это xhr.state (): если он «отклонен», то произошло перенаправление.

Пример успешного обратного вызова:

request.success(function(data, textStatus, xhr)
{
    if(xhr.state() == "resolved")
    {
        //no redirection
    }
    if(xhr.state() == "rejected")
    {
        //redirection
    }
});

Пример с обратным вызовом ошибки:

request.error(function(xhr, textStatus)
{
    if (xhr.state() == "rejected")
    {
        //redirection
        location.href = "loginpage";
    } else
    {
        //some other error happened
        alert("error");
    }
});
Такман
источник
1
Совет в вашем ответе действительно помог нам наладить работу. Для заметок, которые помогут другим, у нас есть WebSphere Portal, безопасность которого интегрирована с SiteMinder. У нас есть портлет, которому требуются Ajax-вызовы URL-адреса ресурса, и когда он истекает, происходит прозрачное перенаправление, но мы нигде не можем понять, как перенаправить на страницу входа. Проверка того, что jqXHR.state () "отклонено", безусловно, помогла. Еще раз большое спасибо.
Уреш Курухури
Отличная находка, однако могут быть ложные срабатывания, поскольку состояние «отклонено» может срабатывать, даже если обещание отклонено, а не только при перенаправлении. jQuery объясняет, когда отправляется состояние «отклонено» api.jquery.com/deferred.state
Nitin
1

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

Я столкнулся с этим тихим перенаправлением 302 в контексте SharePoint. У меня есть простой клиентский код Javascript, который пингует дочерний сайт SharePoint, и если он получает ответ HTTP 200, он перемещается на этот сайт через window.location. Если он получает что-то еще, он уведомляет пользователя о том, что сайт не существует.

Однако в случае, когда сайт существует, но у пользователя нет разрешения, SharePoint автоматически перенаправляет на страницу AccessDenied.aspx. SharePoint уже выполнил подтверждение аутентификации HTTP 401 на уровне сервера / фермы - пользователь имеет доступ к SharePoint. Но доступ к подсайту обрабатывается, я полагаю, с помощью каких-то флагов базы данных. Тихое перенаправление обходит мое предложение «else», поэтому я не могу выдать собственную ошибку. В моем случае это не шоу-стоп - это последовательное предсказуемое поведение. Но это было немного удивительно, и я кое-что узнал о HTTP-запросах в процессе!

Крис ван Хасселт
источник
1

Меня интересовало то же самое, и я не мог найти state()способ упомянутый Такманом, и немного покопался для себя. Ради людей, приходящих сюда в поисках ответа, вот мои выводы:

Как уже неоднократно говорилось, вы не можете предотвратить перенаправления, но вы можете их обнаружить. По MDN вы можете использовать responseURLиз XMLHttpRequestObject, который будет содержать конечный URL ответ пришел, после всех перенаправлений. Единственное предостережение: он не поддерживается Internet Explorer (он есть в Edge). Поскольку xhr/, jqXHRпереданный в функцию success/ donejquery, является расширением фактического XMLHttpRequest, он также должен быть доступен там.

Риалгар
источник
0

Я полагаю, вы получаете ответ 200, потому что во второй раз перенаправления нет, потому что страница 404 не истекает, она сохраняется в кеше. То есть второй раз браузер выдает вам страницу в кеше. В jquery ajax есть свойство "cache". http://api.jquery.com/jQuery.ajax/

Вы должны написать "ложь"

netadictos
источник
0

Хотя отключить следующее перенаправление местоположения в XmlHttpRequests невозможно , это происходит при использовании fetch () :

fetch('url', {redirect: manual});
Cweiske
источник
Fetch не скажет вам, какой был перенаправленный URL. Вы можете отключить это поведение, но «redirect: manual» не предназначен для того, чтобы позволить пользователю обрабатывать перенаправление самостоятельно, имеет намерение имени.
lcjury
-2

Я не уверен, применимо ли это в вашем случае, но вы можете написать код для ответа на определенные коды состояния в функции AJAX -

$.ajax({
    url: '/admin/secret/data',
    type: 'POST',
    contentType: 'application/json; charset=utf-8',
    statusCode: {
        200: function (data) {
            alert('302: Occurred');
            // Bind the JSON data to the UI
        },
        401: function (data) {
            alert('401: Occurred');
            // Handle the 401 error here.
        }
    }
});
ipr101
источник
9
Я не думаю, что это применимо, потому что OP сказал, что он всегда получает код состояния 200 из-за перенаправления, происходящего в фоновом режиме ..
Да, Барри
-4

В заголовках запроса в случае запроса ajax у вас будет следующее

X-Requested-With    XMLHttpRequest

По этому критерию на стороне сервера можно фильтровать запросы.

Gfox
источник
Он хотел проверить ответ, а не запрос (который он уже контролирует)
Да, Барри
Возможно, Gfox предположил, что для запросов ajax, возвращающих 3xx, бессмысленно, вы можете отфильтровать такой запрос и, например, вернуть 403. когда у вас есть веб-сайт, который обслуживает страницы, требующие проверки подлинности с помощью форм, и эти страницы также выполняют вызовы ajax, и вы хотите поместить логику авторизации в одно место, тогда для меня это правильный ответ.
maciejW