Jak uniemożliwić żądaniom ajax podążanie za przekierowaniami przy użyciu jQuery

103

Korzystam z funkcji jQuery ajax, aby uzyskać dostęp do usługi sieciowej, ale serwer zamiast zwracać odpowiedź z kodem stanu opisującym problem, żądanie jest przekierowywane na stronę z nagłówkiem 200, opisującą problem. Nie mogę wprowadzić żadnych zmian, więc muszę jakoś rozwiązać ten problem na kliencie.

Przykład: żądanie trafia do jakiegoś adresu URL, którego nie znaleziono, więc otrzymuję przekierowanie 302 do innej lokalizacji. Wysyłane jest nowe żądanie i otrzymuję 200 OK, co zapobiega uruchomieniu wywołania zwrotnego błędu.

Czy jest jakiś sposób, żebym mógł zapobiec śledzeniu przekierowań przez żądanie AJAX i zamiast tego wywołać wywołanie zwrotne, najlepiej metodę błędu. Alternatywnie, czy można wykryć, czy przekierowanie wystąpiło w kliencie?

Jørgen
źródło
8
To dziwne, że twój backend zgłasza 302 jako nie znaleziono, zamiast 404.
Jake Feasel
Możliwy duplikat funkcji Zapobiegaj przekierowaniu Xmlhttprequest
użytkownik

Odpowiedzi:

96

Uważam, że twoje pytanie jest interesujące, ale problem w całości wydaje mi się raczej nieporozumieniem. Przynajmniej spróbuję wyjaśnić moje rozumienie problemu.

Ciche (przezroczyste) przekierowanie jest częścią XMLHttpRequestspecyfikacji (zobacz tutaj zwłaszcza słowa „… przejrzyste podążaj za przekierowaniem…”). Standard wspomina tylko, że agent użytkownika (przeglądarka internetowa) może zapobiegać niektórym rodzajom automatycznych przekierowań lub powiadamiać o nich, ale nie jest częścią XMLHttpRequest. Jest to część konfiguracji klienta HTTP (konfiguracja systemu operacyjnego) lub konfiguracji przeglądarki internetowej. Więc jQuery.ajaxnie ma żadnej opcji, w której można zapobiec przekierowaniu.

Możesz zobaczyć, że przekierowanie HTTP jest częścią protokołu HTTP, a nie częścią XMLHttpRequest. Więc to jest na innym poziomie abstrakcji lub stosu sieci. Na przykład dane z XMLHttpRequestserwera można pobrać z serwera proxy HTTP lub z lokalnej pamięci podręcznej przeglądarki i jest to część protokołu HTTP. Na buforowanie ma wpływ głównie serwer, który dostarcza dane, a nie klient.

Możesz porównać wymagania ze swojego pytania z wymogiem zapobiegania zmianie adresu IP serwera WWW lub zmianie trasy IP podczas komunikacji. Wszystkie rzeczy mogą być interesujące w niektórych scenariuszach, ale istnieją części innego poziomu stosu komunikacyjnego i nie można nimi zarządzać za pomocą jQuery.ajaxlub XMLHttpRequest.

XMLHttpRequestStandardowy powiedzmy, że konfiguracja klient może mieć opcje, które uniemożliwiają przekierowanie. W przypadku „świata Microsoft”, który lepiej znam, można spojrzeć na funkcję WinHttpSetOption, która służy do ustawiania WINHTTP_OPTION_DISABLE_FEATUREopcji z WINHTTP_DISABLE_REDIRECTSwartością. Innym sposobem jest użycie WINHTTP_OPTION_REDIRECT_POLICYopcji z WINHTTP_OPTION_REDIRECT_POLICY_NEVERwartością. Kolejną funkcją, której można użyć w systemie Windows, jest funkcja WinHttpSetStatusCallback, która może ustawić funkcję wywołania zwrotnego, która odbiera niektóre powiadomienia, takie jak WINHTTP_CALLBACK_FLAG_REDIRECT.

Można więc generalnie zaimplementować swoje wymagania, ale rozwiązanie prawdopodobnie nie będzie niezależne od systemu operacyjnego czy przeglądarki internetowej i nie będzie na poziomie jQuery.ajaxlub XMLHttpRequest.

Oleg
źródło
2
Doskonała odpowiedź z dużym wglądem! Mam pewne doświadczenie z curl, dla którego można ustawić podobne flagi, o których wspomniałeś. Miałem nadzieję, że takie instrukcje mogą zostać przekazane do przeglądarki, ale z Twojej odpowiedzi rozumiem, że oczekiwanym zachowaniem będzie podążanie za przekierowaniami tak, jakby początkowe żądanie zostało wysłane do lokalizacji wyznaczonej przez serwer.
Jørgen
@ Jørgen: Nie ma za co! W większości scenariuszy przekierowanie nie stanowi żadnego problemu. Nie opisujesz kontekstu, w którym używasz jQuery.ajax i czy masz pełną kontrolę nad serwerem WWW, do którego wysyłasz żądanie. Dlatego trudno jest udzielić ci innych porad, które naprawdę mogą rozwiązać twój problem.
Oleg
Obawiam się, że nie kontroluję strony serwera. Myślę, że najlepszą opcją jest przeanalizowanie lub zweryfikowanie treści odpowiedzi.
Jørgen
@ Jørgen: Dlaczego przekierowanie jest problemem w Twoim przypadku? Jeśli serwer tymczasowo lub na stałe przeniósł jakąś stronę do innej lokalizacji, może przekierować pierwotne żądanie do nowej lokalizacji. Wszystko będzie w porządku. Administrator może skonfigurować serwer WWW, aby wykonywał przekierowania, na przykład podczas operacji przywracania na serwerze lub innych prac pomocniczych. Jeśli poprosisz serwer o adres URL mający DNS, administrator może zmienić mapowanie IP na inny serwer. Potrafi przekierować HTTP w taki sam sposób, jak rekonfigurację DNS. Jaki masz problem?
Oleg
Mój problem polega na tym, że przekierowanie prowadzi do ogólnej strony błędu. Wiem, że serwer powinien być skonfigurowany inaczej, ale na razie będę musiał znaleźć rozwiązanie tej sytuacji, tak jak jest.
Jørgen
23

Nie wierzę, że to możliwe. Biblioteka bazowa (XHR) sprawia, że ​​nowe żądanie jest przejrzyste. Biorąc to pod uwagę, to, co zrobiłem w takich sytuacjach (zwykle w przypadku transakcji typu timeout sesji, która przenosi mnie na stronę logowania), to odesłanie niestandardowego nagłówka odpowiedzi. Skonfigurowałem również globalną obsługę AJAX, która sprawdza obecność tego nagłówka i odpowiednio reaguje, gdy jest obecny (na przykład przekierowuje całą stronę do ekranu logowania).

Jeśli jesteś zainteresowany, oto kod jQuery, na który muszę zwrócić uwagę na ten niestandardowy nagłówek:

/* 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)
Jake Feasel
źródło
1
Dzięki, myślę, że będę musiał zadowolić się podobnym podejściem, analizując odpowiedź.
Jørgen
11

Znalazłem funkcję, która pozwala sprawdzić, czy Twoje połączenie zostało przekierowane. To xhr.state (): jeśli jest „odrzucona”, następuje przekierowanie.

Przykład z pomyślnym oddzwonieniem:

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

Przykład z wywołaniem zwrotnym błędu:

request.error(function(xhr, textStatus)
{
    if (xhr.state() == "rejected")
    {
        //redirection
        location.href = "loginpage";
    } else
    {
        //some other error happened
        alert("error");
    }
});
Takman
źródło
1
Wskazówka w Twojej odpowiedzi naprawdę pomogła nam w pracy. Ze względu na uwagi, które mogą pomóc innym, udostępniliśmy produkt WebSphere Portal zintegrowany z zabezpieczeniami SiteMinder. Mamy portlet, który wymaga wywołań Ajax do adresu URL zasobu, a po przekroczeniu limitu czasu pojawiają się w nim przezroczyste przekierowania, ale nigdzie nie wiemy, jak przekierować na stronę logowania. Sprawdzanie, czy jqXHR.state () jest „odrzucana” z pewnością pomogło. Jeszcze raz wielkie dzięki.
Uresh Kuruhuri
Świetne odkrycie, jednak mogą występować fałszywe alarmy, ponieważ stan „odrzucony” może zostać wyzwolony, nawet jeśli obietnica zostanie odrzucona, a nie tylko przy przekierowaniu. jQuery wyjaśnia, kiedy wysyłany jest stan „odrzucony” api.jquery.com/deferred.state
Nitin
1

Nie mogę dodać do wnikliwej mądrości poprzednich programistów, którzy odpowiedzieli, ale dodam konkretny przypadek, o którym inni mogą się przydać.

Natknąłem się na to ciche przekierowanie 302 w kontekście SharePoint. Mam prosty kod klienta JavaScript, który pinguje podstronę SharePoint, a jeśli otrzyma odpowiedź HTTP 200, zostanie przeniesiony do tej witryny za pośrednictwem window.location. Jeśli otrzyma cokolwiek innego, informuje użytkownika, że ​​witryna nie istnieje.

Jednak w przypadku, gdy witryna istnieje, ale użytkownik nie ma uprawnień, program SharePoint po cichu przekierowuje do strony AccessDenied.aspx. SharePoint wykonał już uzgadnianie uwierzytelniania HTTP 401 na poziomie serwera / farmy - użytkownik ma dostęp do SharePoint. Ale dostęp do podstrony jest obsługiwany, jak przypuszczam, za pomocą jakiegoś rodzaju flag bazy danych. Ciche przekierowanie pomija moją klauzulę „else”, więc nie mogę zgłosić własnego błędu. W moim przypadku nie jest to żadna przeszkoda - to konsekwentne przewidywalne zachowanie. Ale było to trochę zaskakujące i dowiedziałem się czegoś o żądaniach HTTP w tym procesie!

Chris van Hasselt
źródło
1

Interesowało mnie to samo i nie mogłem znaleźć state()metody wspomnianej przez Takmana i trochę poszperałem dla siebie. Ze względu na ludzi, którzy pojawiają się tutaj w poszukiwaniu odpowiedzi, oto moje ustalenia:

Jak stwierdzono wielokrotnie, nie możesz zapobiec przekierowaniom, ale możesz je wykryć. Według MDN , po wszystkich przekierowaniach możesz użyć responseURLof the XMLHttpRequestObject, który będzie zawierał końcowy adres URL, z którego pochodzi odpowiedź. Jedynym zastrzeżeniem jest to, że nie jest obsługiwany przez Internet Explorer (ma go Edge). Ponieważ xhr/ jqXHRprzekazane do funkcji success/ donejquery jest rozszerzeniem rzeczywistej XMLHttpRequest, powinno być tam również dostępne.

Rialgar
źródło
0

Przypuszczam, że otrzymujesz odpowiedź 200, ponieważ za drugim razem nie ma przekierowania, ponieważ strona 404 nie wygasa, jest zapisywana w pamięci podręcznej. To znaczy, że za drugim razem przeglądarka udostępni stronę w pamięci podręcznej. W pliku AJAX jquery znajduje się właściwość „cache”. http://api.jquery.com/jQuery.ajax/

Powinieneś napisać to jako „fałsz”

netadictos
źródło
0

Chociaż nie jest możliwe wyłączenie śledzenia przekierowań lokalizacji w XmlHttpRequests , dzieje się tak podczas korzystania z funkcji fetch () :

fetch('url', {redirect: manual});
cweiske
źródło
Funkcja pobierania nie powie Ci, jaki był przekierowany adres URL. Możesz wyłączyć to zachowanie, ale „przekierowanie: ręczne” nie ma na celu umożliwienia użytkownikowi obsługi przekierowania na własną rękę ma intencje nazwy.
lcjury
-2

Nie jestem pewien, czy będzie to miało zastosowanie w Twoim przypadku, ale możesz napisać kod odpowiadający na określone kody statusu w funkcji 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
źródło
9
Nie sądzę, żeby to miało zastosowanie, ponieważ OP powiedział, że zawsze otrzymuje kod statusu 200 z powodu przekierowania w tle ..
Tak Barry
-4

W nagłówkach żądań w przypadku żądania AJAX będziesz mieć następujące dane

X-Requested-With    XMLHttpRequest

Według tych kryteriów po stronie serwera można filtrować żądania.

Gfox
źródło
Chciał sprawdzić odpowiedź, a nie prośbę (nad którą już ma kontrolę)
Tak Barry.
Może Gfox zasugerował, że dla żądań ajax zwracanie 3xx nie ma sensu, możesz filtrować tego rodzaju żądania i na przykład zwracać 403. jeśli masz witrynę, która obsługuje strony wymagające uwierzytelniania za pomocą formularzy i te strony również wykonują wywołania ajax i chcesz umieścić logikę autoryzacji w jednym miejscu, to dla mnie jest to poprawna odpowiedź.
maciejW