Cómo evitar que las solicitudes ajax sigan redireccionamientos usando jQuery

102

Utilizo las funciones de jQuery ajax para acceder a un servicio web, pero el servidor, en lugar de devolver una respuesta con un código de estado que describe un problema, la solicitud se redirige a una página con un encabezado 200, que describe el problema. No puedo hacer ningún cambio en esto, así que necesito resolverlo en el cliente de alguna manera.

Ejemplo: una solicitud va a alguna URL que no se encuentra, por lo que recibo un redireccionamiento 302 a otra ubicación. Se envía una nueva solicitud y recibo 200 OK, evitando así que se active la devolución de llamada de error.

¿Hay alguna manera de evitar que la solicitud ajax siga las redirecciones y, en su lugar, invoque una devolución de llamada, preferiblemente el método de error? Alternativamente, ¿es posible detectar si se ha producido una redirección en el cliente?

Jørgen
fuente
8
Es extraño que su backend informe 302 para no encontrado, en lugar de 404.
Jake Feasel
Posible duplicado de Prevenir la redirección de Xmlhttprequest
usuario

Respuestas:

96

Encuentro su pregunta interesante, pero el problema en su conjunto me parece más un malentendido. Al menos intentaré explicar mi comprensión del problema.

La redirección silenciosa (transparente) es parte de la XMLHttpRequestespecificación (vea aquí especialmente las palabras "... siga de forma transparente la redirección ..."). El estándar solo menciona que el agente de usuario (el navegador web) puede prevenir o notificar ciertos tipos de redirecciones automáticas, pero no es parte de XMLHttpRequest. Es parte de la configuración del cliente HTTP (configuración del sistema operativo) o la configuración del navegador web. Por jQuery.ajaxlo tanto , no puede tener ninguna opción en la que pueda evitar la redirección.

Puede ver que la redirección HTTP es parte del protocolo HTTP y no parte de XMLHttpRequest. Así que está en otro nivel de abstracción o pila de red. Por ejemplo, los datos del XMLHttpRequestse pueden recuperar del proxy HTTP o del caché del navegador local, y es parte del protocolo HTTP. Principalmente, el servidor que proporciona los datos y no el cliente puede influir en el almacenamiento en caché.

Puede comparar el requisito de su pregunta con el requisito de evitar el cambio de la dirección IP del servidor web o el cambio de la ruta IP durante la comunicación. Todas las cosas pueden ser interesantes en algunos escenarios, pero hay partes de otro nivel de la pila de comunicación y no pueden ser administradas por jQuery.ajaxo XMLHttpRequest.

El XMLHttpRequestestándar dice que la configuración del cliente puede tener opciones que eviten la redirección. En el caso del "mundo de Microsoft", que conozco mejor, puede mirar la función WinHttpSetOption que se puede usar para establecer la WINHTTP_OPTION_DISABLE_FEATUREopción con el WINHTTP_DISABLE_REDIRECTSvalor. Otra forma es el uso de la WINHTTP_OPTION_REDIRECT_POLICYopción con el WINHTTP_OPTION_REDIRECT_POLICY_NEVERvalor. Una característica más que se puede usar en Windows es la función WinHttpSetStatusCallback que puede configurar la función de devolución de llamada que recibió algunas notificaciones como WINHTTP_CALLBACK_FLAG_REDIRECT.

Por lo tanto, es posible implementar sus requisitos en general, pero la solución probablemente no será independiente del sistema operativo o del navegador web y no estará al nivel de jQuery.ajaxo XMLHttpRequest.

Oleg
fuente
2
¡Excelente respuesta con gran perspicacia! Tengo algo de experiencia con curl, por lo que puede establecer banderas similares a las que menciona. Esperaba que tales instrucciones pudieran pasarse al navegador, pero por su respuesta, entiendo que el comportamiento esperado sería seguir las redirecciones como si la solicitud inicial fuera enviada a la ubicación asignada por el servidor.
Jørgen
@ Jørgen: ¡De nada! En la mayoría de los escenarios, la redirección no es un problema en absoluto. No describe el contexto en el que usa jQuery.ajax y si tiene control total sobre el servidor web al que envía la solicitud. Por eso es difícil darte otros consejos que realmente puedan resolver tu problema.
Oleg
No controlo el lado del servidor, me temo. Supongo que mi mejor opción es analizar o validar el contenido de la respuesta.
Jørgen
@ Jørgen: ¿Por qué la redirección es un problema en su caso? Si el servidor movió alguna página a otra ubicación de forma temporal o permanente, puede redirigir su solicitud original a la nueva ubicación. Estará absolutamente bien. Un administrador puede configurar el servidor web para realizar la redirección, por ejemplo, durante la operación de restauración en el servidor o cualquier otro trabajo de soporte. Si le pregunta al servidor por URL que tenga DNS, el administrador puede cambiar la asignación de IP a otro servidor. Puede realizar la redirección HTTP de la misma manera que la reconfiguración de DNS. ¿Cual es tu problema?
Oleg
Mi problema es que la redirección va a una página de error genérica. Sé que el servidor debe configurarse de manera diferente, pero por ahora tendré que encontrar una solución para esta situación tal como está.
Jørgen
23

No creo que sea posible. La biblioteca subyacente (XHR) realiza la nueva solicitud de forma transparente. Dicho esto, lo que he hecho en estas situaciones (generalmente un tipo de trato de tiempo de espera de sesión que me lleva a una página de inicio de sesión) es enviar un encabezado de respuesta personalizado. También configuré un controlador ajax global que verifica la presencia de ese encabezado y responde apropiadamente cuando está presente (por ejemplo, redirigiendo toda la página a la pantalla de inicio de sesión).

En caso de que esté interesado, aquí está el código jQuery que debo vigilar para ese encabezado personalizado:

/* 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
fuente
1
Gracias, creo que tendré que conformarme con un enfoque similar, analizando la respuesta.
Jørgen
11

Encontré una función para verificar si su llamada ha sido redirigida. Es xhr.state (): si es "rechazado", entonces ocurrió una redirección.

Ejemplo con devolución de llamada exitosa:

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

Ejemplo con devolución de llamada de error:

request.error(function(xhr, textStatus)
{
    if (xhr.state() == "rejected")
    {
        //redirection
        location.href = "loginpage";
    } else
    {
        //some other error happened
        alert("error");
    }
});
Takman
fuente
1
El consejo en su respuesta realmente nos ayudó a hacer que las cosas funcionen. Por el bien de las notas que ayudarían a otros, tenemos WebSphere Portal que tiene su seguridad integrada con SiteMinder. Tenemos un portlet que necesita llamadas Ajax a una URL de recurso y, cuando se agota, tiene redireccionamientos transparentes, pero no sabemos cómo redireccionar a la página de inicio de sesión. Verificar que jqXHR.state () sea "rechazado" seguramente ayudó. Muchas gracias de nuevo.
Uresh Kuruhuri
Gran hallazgo, sin embargo, puede haber falsos positivos ya que el estado "rechazado" puede activarse incluso si se rechaza una promesa y no solo en la redirección. jQuery explica cuándo se envía el estado "rechazado" api.jquery.com/deferred.state
Nitin
1

No puedo agregar a la perspicaz sabiduría de los codificadores anteriores que han respondido, pero agregaré un caso específico que otros pueden encontrar útil para conocer.

Encontré este redireccionamiento silencioso 302 en el contexto de SharePoint. Tengo un código de cliente Javascript simple que hace ping a un subsitio de SharePoint, y si recibe una respuesta HTTP 200, se traslada a ese sitio, vía window.location. Si recibe algo más, le da al usuario un aviso de que el sitio no existe.

Sin embargo, en el caso de que el sitio exista pero el usuario no tenga permiso, SharePoint redirige silenciosamente a una página AccessDenied.aspx. SharePoint ya realizó el protocolo de enlace de autenticación HTTP 401 a nivel de servidor / granja: el usuario tiene acceso a SharePoint. Pero el acceso al subsitio se maneja, supongo, usando indicadores de base de datos de algún tipo. El redireccionamiento silencioso pasa por alto mi cláusula "else", por lo que no puedo lanzar mi propio error. En mi caso, esto no es un obstáculo, es un comportamiento predecible consistente. Pero fue un poco sorprendente, ¡y aprendí algo sobre las solicitudes HTTP en el proceso!

Chris van Hasselt
fuente
1

Estaba interesado en lo mismo y no pude encontrar el state()método mencionado por Takman e investigué un poco por mí mismo. Por el bien de las personas que se presenten aquí en busca de una respuesta, aquí están mis hallazgos:

Como se indicó varias veces, no puede evitar las redirecciones, pero puede detectarlas. De acuerdo con MDN , puede usar el responseURLde XMLHttpRequestObject, que contendrá la URL final de la que proviene la respuesta, después de todas las redirecciones. La única advertencia es que no es compatible con Internet Explorer (Edge lo tiene). Dado que el xhr/ jqXHRpasado a la función success/ donede jquery es una extensión del real XMLHttpRequest, también debería estar disponible allí.

Rialgar
fuente
0

Supongo que recibes una respuesta 200 porque la segunda vez no hay redirección, porque la página 404 no caduca, se guarda en la caché. Es decir que la segunda vez que el navegador te da la página en el caché. Hay una propiedad "caché" en el jquery ajax. http://api.jquery.com/jQuery.ajax/

Deberías escribirlo en "falso"

netadictos
fuente
0

Si bien no es posible deshabilitar la redirección de ubicación siguiente en XmlHttpRequests , lo es cuando se usa fetch () :

fetch('url', {redirect: manual});
cweiske
fuente
Fetch no le dirá cuál fue la URL redirigida. Puede deshabilitar el comportamiento, pero "redirect: manual" no tiene la intención de permitir que el usuario maneje el redireccionamiento él mismo tiene las intenciones de nombre.
lcjury
-2

No estoy seguro de si esto se aplicará en su caso, pero puede escribir código para responder a códigos de estado específicos en la función 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
fuente
9
No creo que esto se aplique porque OP dijo que siempre obtiene un código de estado 200 debido a que la redirección ocurre en segundo plano ..
Sí Barry
-4

En los encabezados de solicitud en el caso de una solicitud ajax, tendrá lo siguiente

X-Requested-With    XMLHttpRequest

Según este criterio en el lado del servidor, puede filtrar las solicitudes.

Gfox
fuente
Quería verificar la respuesta, no la solicitud (sobre la que ya tiene control)
Sí Barry
Tal vez Gfox sugirió que para las solicitudes ajax que devuelven 3xx no tienen sentido, puede filtrar este tipo de solicitud y devolver 403, por ejemplo. cuando tiene un sitio web que sirve páginas que requieren autenticación de formularios y esas páginas también hacen llamadas ajax y desea poner la lógica de autorización en un solo lugar, para mí es una respuesta válida.
maciejW