Come impedire alle richieste ajax di seguire i reindirizzamenti utilizzando jQuery


102

Uso le funzioni jQuery ajax per accedere a un servizio web, ma il server, invece di restituire una risposta con un codice di stato che descrive un problema, la richiesta viene reindirizzata a una pagina con un'intestazione 200, che descrive il problema. Non posso apportare modifiche a questo, quindi devo risolverlo in qualche modo sul client.

Esempio: una richiesta va a un URL che non viene trovato, quindi ricevo un reindirizzamento 302 a un'altra posizione. Viene inviata una nuova richiesta e ricevo 200 OK, impedendo così l'attivazione della richiamata di errore.

C'è un modo per impedire alla richiesta ajax di seguire i reindirizzamenti e invocare invece un callback, preferibilmente il metodo di errore. In alternativa, è possibile rilevare se si è verificato un reindirizzamento nel client?



8
È strano che il tuo backend
indichi

Risposte:


96

Trovo la tua domanda interessante, ma il problema nel complesso mi sembra più un malinteso. Almeno cercherò di spiegare la mia comprensione del problema.

Il reindirizzamento silenzioso (trasparente) è la parte delle XMLHttpRequestspecifiche (vedere qui in particolare le parole "... seguire in modo trasparente il reindirizzamento ..."). Lo standard menziona solo che l'agente utente (il browser web) può impedire o notificare certi tipi di reindirizzamenti automatici, ma non fa parte di XMLHttpRequest. Fa parte della configurazione del client HTTP (configurazione del sistema operativo) o della configurazione del browser web. Quindi jQuery.ajaxnon puoi avere alcuna opzione in cui puoi impedire il reindirizzamento.

Puoi vedere che il reindirizzamento HTTP fa parte del protocollo HTTP e non fa parte di XMLHttpRequest. Quindi è su un altro livello di astrazione o sullo stack di rete. Ad esempio, i dati da XMLHttpRequestpossono essere recuperati dal proxy HTTP o dalla cache del browser locale, ed è la parte del protocollo HTTP. Per lo più il server che fornisce i dati e non il client può influenzare il caching.

È possibile confrontare il requisito della domanda con il requisito per impedire la modifica dell'indirizzo IP del server Web o la modifica del percorso IP durante la comunicazione. Tutte le cose possono essere interessanti in alcuni scenari, ma ci sono parti di un altro livello dello stack di comunicazione e non possono essere gestite da jQuery.ajaxo XMLHttpRequest.

Lo XMLHttpRequeststandard dice che la configurazione del client può avere opzioni che impediscono il reindirizzamento. In caso di "mondo Microsoft", che conosco meglio, puoi guardare la funzione WinHttpSetOption che può essere utilizzata per impostare l' WINHTTP_OPTION_DISABLE_FEATUREopzione con il WINHTTP_DISABLE_REDIRECTSvalore. Un altro modo è l'utilizzo WINHTTP_OPTION_REDIRECT_POLICYdell'opzione con il WINHTTP_OPTION_REDIRECT_POLICY_NEVERvalore. Un'altra caratteristica che è possibile utilizzare in Windows è la funzione WinHttpSetStatusCallback che può impostare la funzione di callback ricevuta da alcune notifiche come WINHTTP_CALLBACK_FLAG_REDIRECT.

Quindi è possibile implementare i tuoi requisiti in generale, ma la soluzione probabilmente non sarà indipendente dal sistema operativo o dal browser web e non sarà al livello di jQuery.ajaxo XMLHttpRequest.


2
Ottima risposta con grande intuizione! Ho una certa esperienza con curl, per il quale puoi impostare flag simili come hai menzionato. Speravo che tali istruzioni potessero essere passate al browser, ma dalla tua risposta, capisco che il comportamento previsto sarebbe quello di seguire i reindirizzamenti come se la richiesta iniziale fosse stata inviata alla posizione assegnata dal server.
Jørgen

@ Jørgen: sei il benvenuto! Nella maggior parte degli scenari il reindirizzamento non è affatto un problema. Non descrivi il contesto in cui usi jQuery.ajax e se hai il pieno controllo sul server web a cui invii la richiesta. Quindi è difficile darti altri consigli che possono davvero risolvere il tuo problema.
Oleg

Non controllo il lato server, temo. Immagino che la mia migliore opzione sia analizzare o convalidare il contenuto della risposta.
Jørgen

@ Jørgen: Perché il reindirizzamento è un problema nel tuo caso? Se il server ha spostato una pagina in un'altra posizione temporaneamente o permanentemente, può reindirizzare la richiesta originale alla nuova posizione. Sarà assolutamente OK. Un amministratore può configurare il server Web per eseguire il reindirizzamento, ad esempio durante l'operazione di ripristino sul server o qualsiasi altro lavoro di supporto. Se chiedi al server tramite URL con DNS, l'amministratore può modificare la mappatura IP su un altro server. Può eseguire il reindirizzamento HTTP allo stesso modo della riconfigurazione DNS. Qual è il tuo problema?
Oleg

Il mio problema è che il reindirizzamento va a una pagina di errore generica. So che il server dovrebbe essere configurato in modo diverso, ma per ora dovrò trovare una soluzione per questa situazione così com'è.
Jørgen

23

Non credo sia possibile. La libreria sottostante (XHR) effettua la nuova richiesta in modo trasparente. Detto questo, quello che ho fatto in queste situazioni (di solito un tipo di contratto di timeout della sessione che mi porta a una pagina di accesso) è stato restituito un'intestazione di risposta personalizzata. Ho anche configurato un gestore Ajax globale che controlla la presenza di tale intestazione e risponde in modo appropriato quando presente (ad esempio, reindirizzando l'intera pagina alla schermata di accesso).

Nel caso tu sia interessato, ecco il codice jQuery che devo guardare per quell'intestazione personalizzata:

/* 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
Grazie, immagino che dovrò accontentarmi di un approccio simile, analizzando la risposta.
Jørgen

11

Ho trovato una funzione per verificare se la tua chiamata è stata reindirizzata. È xhr.state (): se è "rifiutato", si è verificato un reindirizzamento.

Esempio con callback di successo:

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

Esempio con callback di errore:

request.error(function(xhr, textStatus)
{
    if (xhr.state() == "rejected")
    {
        //redirection
        location.href = "loginpage";
    } else
    {
        //some other error happened
        alert("error");
    }
});

1
Il suggerimento nella tua risposta ci ha davvero aiutato a far funzionare le cose. Per motivi di note che potrebbero aiutare gli altri, abbiamo WebSphere Portal con la sua sicurezza integrata con SiteMinder. Abbiamo un portlet che necessita di chiamate Ajax a un URL di risorsa e quando scade, si verificano reindirizzamenti trasparenti ma non siamo in grado di gestire da nessuna parte come reindirizzare alla pagina di accesso. Controllare che jqXHR.state () fosse "rifiutato" sicuramente aiutato. Molte grazie ancora.
Uresh Kuruhuri

Ottima scoperta, tuttavia possono esserci falsi positivi poiché lo stato "rifiutato" può essere attivato anche se una promessa viene rifiutata e non solo in caso di reindirizzamento. jQuery spiega quando lo stato "rifiutato" viene inviato api.jquery.com/deferred.state
Nitin

1

Non posso aggiungere alla saggezza perspicace dei precedenti programmatori che hanno risposto, ma aggiungerò un caso specifico che altri potrebbero trovare utile sapere.

Mi sono imbattuto in questo reindirizzamento silenzioso 302 nel contesto di SharePoint. Ho un semplice codice client Javascript che esegue il ping di un sito secondario di SharePoint e, se riceve una risposta HTTP 200, si trasferisce a quel sito, tramite window.location. Se riceve qualcos'altro, avvisa l'utente che il sito non esiste.

Tuttavia, nel caso in cui il sito esista ma l'utente non dispone dell'autorizzazione, SharePoint reindirizza automaticamente a una pagina AccessDenied.aspx. SharePoint ha già eseguito l'handshake dell'autenticazione HTTP 401 a livello di server / farm: l'utente ha accesso a SharePoint. Ma l'accesso al sito secondario è gestito suppongo utilizzando flag di database di qualche tipo. Il reindirizzamento silenzioso ignora la mia clausola "else", quindi non posso sollevare il mio errore. Nel mio caso, questo non è un ostacolo allo spettacolo: è un comportamento prevedibile coerente. Ma è stato un po 'sorprendente e ho imparato qualcosa sulle richieste HTTP nel processo!


1

Ero interessato alla stessa cosa e non sono riuscito a trovare il state()metodo menzionato da Takman e ho scavato un po 'da solo. Per il bene delle persone che si presentano qui in cerca di una risposta, ecco i miei risultati:

Come affermato più volte, non è possibile impedire i reindirizzamenti, ma è possibile rilevarli. Secondo MDN è possibile utilizzare il responseURLdel XMLHttpRequestObject, che conterrà l'URL finale da cui proviene la risposta, dopo tutti i reindirizzamenti. L'unico avvertimento è che non è supportato da Internet Explorer (Edge lo ha). Poiché il xhr/ jqXHRpassato nella funzione success/ donedi jquery è un'estensione dell'attuale XMLHttpRequest, dovrebbe essere disponibile anche lì.


0

Suppongo che tu riceva una risposta 200 perché la seconda volta non c'è reindirizzamento, perché la pagina 404 non scade, viene salvata nella cache. Vale a dire che la seconda volta che il browser ti dà la pagina nella cache. C'è una proprietà "cache" nel jquery ajax. http://api.jquery.com/jQuery.ajax/

Dovresti scriverlo su "false"


0

Sebbene non sia possibile disabilitare il reindirizzamento della posizione in XmlHttpRequests , lo è quando si utilizza fetch () :

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

Fetch non ti dirà qual era l'URL reindirizzato. È possibile disabilitare il comportamento, ma "redirect: manual" non ha lo scopo di consentire all'utente di gestire il reindirizzamento da solo ha il nome intent.
lcjury

-2

Non sono sicuro che questo si applicherà al tuo caso, ma puoi scrivere codice per rispondere a codici di stato specifici nella funzione 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
Non penso che questo si applichi perché OP ha detto che ottiene sempre un codice di stato 200 a causa del reindirizzamento in background ..
Sì Barry

-4

Nelle intestazioni della richiesta nel caso di una richiesta ajax avrai quanto segue

X-Requested-With    XMLHttpRequest

Con questo criterio sul lato server puoi filtrare le richieste.


Voleva controllare la risposta non la richiesta (su cui ha già il controllo)
Sì Barry

Forse Gfox ha suggerito che per le richieste ajax che restituiscono 3xx sono inutili, potresti filtrare questo tipo di richiesta e restituire 403 per esempio. quando hai un sito web che serve pagine che richiedono l'autenticazione di moduli e quelle pagine effettuano anche chiamate ajax e vuoi mettere la logica di autorizzazione in un unico posto, allora per me è una risposta valida.
maciejW
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.