Як запобігти запитам ajax слідувати за переадресаціями за допомогою jQuery


103

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

Приклад: Запит переходить на деяку URL-адресу, яку не знайдено, тому я отримую переспрямування 302 на інше місце. Надсилається новий запит, і я отримую 200 ОК, тим самим запобігаючи запуску зворотного дзвінка помилки.

Чи я можу запобігти запиту ajax слідувати за переадресаціями та замість цього викликати зворотний виклик, бажано метод помилки. Як варіант, чи можна виявити, чи перенаправлення трапилось у клієнта?



8
Дивно, що ваш бекенд повідомляє 302 за не знайдений, а не 404.
Джейк Фезель

Відповіді:


96

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

Мовчазне (прозоре) перенаправлення є частиною XMLHttpRequestспецифікації (див. Тут особливо слова "... прозоро слідуйте за переадресацією ..."). У стандарті згадується лише те, що користувальницький агент (веб-браузер) може запобігати або повідомляти про певні види автоматичних переадресацій, але це не є частиною XMLHttpRequest. Це частина конфігурації клієнта HTTP (конфігурація ОС) або конфігурація веб-браузера. Тому jQuery.ajaxне може бути жодної опції, де можна запобігти перенаправлення.

Ви можете бачити, що перенаправлення HTTP є частиною протоколу HTTP, а не частиною XMLHttpRequest. Значить, це на іншому рівні абстракції або мережевому стеку. Наприклад, дані з XMLHttpRequestcan можна отримати з HTTP-проксі або з локального кешу браузера, і це частина протоколу HTTP. Переважно сервер, який надає дані, а не клієнт, може впливати на кешування.

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

У XMLHttpRequestстандарті сказано, що в конфігурації клієнта можуть бути параметри, які перешкоджають перенаправленню. У випадку "Майкрософт", який я краще знаю, ви можете подивитися функцію 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
Нітін

1

Я не можу додати проникливої ​​мудрості попередніх кодерів, які відповіли, але я додам конкретний випадок, про який можуть виявитися корисними інші.

Я натрапив на це 302 мовчазне переспрямування в контексті SharePoint. У мене є простий код клієнта Javascript, який надсилає під-сайт SharePoint, і якщо він отримує відповідь 200 HTTP, він переселяється на цей сайт через window.location. Якщо він отримує щось інше, він повідомляє користувачеві про те, що сайт не існує.

Однак у випадку, коли сайт існує, але користувач не має дозволу, SharePoint мовчки переспрямовує на сторінку AccessDenied.aspx. SharePoint вже здійснив рукостискання аутентифікації HTTP 401 на рівні сервера / ферми - користувач має доступ до SharePoint. Але доступ до під-сайту обробляється, я думаю, використовуючи якісь прапори бази даних. Мовчазне переспрямування обходить мій пункт "else", тому я не можу підкинути власну помилку. У моєму випадку це не стоп-шоу, це послідовна передбачувана поведінка. Але це було трохи дивно, і я дізнався щось про HTTP запити в процесі!


1

Мене цікавило те саме, і я не міг знайти state()метод, згаданий Такманом, і трохи копав для себе. Заради того, що люди звертаються сюди в пошуках відповіді, ось мої висновки:

Як зазначено кілька разів, перенаправлення не можна запобігти, але ви можете їх виявити. За MDN ви можете використовувати responseURLз XMLHttpRequestObject, який буде містити кінцевий URL відповідь прийшла, після всіх перенаправлень. Тільки застереження полягає в тому, що він не підтримується Internet Explorer (у Edge є). Оскільки xhr/ jqXHRпереданий у success/ doneфункцію jquery є розширенням фактичного XMLHttpRequest, він також повинен бути доступний і там.


0

Я припускаю, що ви отримаєте відповідь 200, оскільки другий раз перенаправлення не відбувається, оскільки сторінка 404 не закінчується, вона зберігається в кеші. Тобто, що вдруге браузер надає вам сторінку в кеш. У jjaery ajax є властивість "кеш". http://api.jquery.com/jQuery.ajax/

Ви повинні написати це "false"


0

Хоча в XmlHttpRequests неможливо відключити переадресацію місцеположення , це при використанні fetch () :

fetch('url', {redirect: manual});

Вибір не скаже вам, що було переспрямованою URL-адресою. Ви можете відключити поведінку, але "перенаправлення: посібник" не призначений для того, щоб користувач міг керувати переадресацією, а сам має наміри імені.
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.
        }
    }
});

9
Я не думаю, що це стосується, оскільки ОП заявив, що він завжди отримує код статусу 200 через переадресацію, що відбувається у фоновому режимі ..
Так, Баррі

-4

У заголовках запитів у разі запиту ajax у вас буде наступне

X-Requested-With    XMLHttpRequest

За цими критеріями на стороні сервера ви можете фільтрувати запити.


Він хотів перевірити відповідь не на запит (над яким він уже має контроль)
Так, Баррі

Можливо, Gfox запропонував, що для запитів ajax, що повертають 3xx, безглуздо, ви можете відфільтрувати такий запит і повернути 403, наприклад. коли у вас є веб-сайт, який обслуговує сторінки, для яких потрібна автентифікація форм, і ці сторінки також здійснюють дзвінки ajax, і ви хочете розмістити логіку авторизації в одному місці, то для мене це правильна відповідь.
maciejW
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.