IE9 jQuery AJAX con CORS devuelve "Acceso denegado"

123

Lo siguiente funciona en todos los navegadores excepto IE (estoy probando en IE 9).

jQuery.support.cors = true;
...
        $.ajax(
            url + "messages/postMessageReadByPersonEmail",
            {
                crossDomain: true,
                data: {
                    messageId       : messageId,
                    personEmail     : personEmail
                },
                success: function() {
                    alert('marked as read');
                },
                error: function(a,b,c) {
                    alert('failed');
                },
                type: 'post'
            }
        );

Tengo otra función que usa dataType: 'jsonp', pero no necesito ningún dato devuelto en esta llamada AJAX. Mi último recurso será devolver algunas tonterías envueltas en JSONP solo para que funcione.

¿Alguna idea de por qué IE está arruinando una solicitud CORS que no devuelve datos?

Garrett
fuente
Dado que ninguna de las respuestas propuestas funcionó para mí (también tuve que pasar cookies a la solicitud CORS, que es un no-no cuando uso XDomainRequest), aquí hay una solución : blog.gauffin.org/2014/04/… . Proxy al rescate! : p
wimvds

Respuestas:

150

Este es un error conocido con jQuery. El equipo de jQuery "no tiene planes de admitir esto en el núcleo y es más adecuado como complemento". (Ver este comentario ). IE no usa XMLHttpRequest , sino un objeto alternativo llamado XDomainRequest .

No es un plugin disponible para apoyar esto en jQuery, que se puede encontrar aquí : https://github.com/jaubourg/ajaxHooks/blob/master/src/xdr.js

EDITAR La función $.ajaxTransportregistra una fábrica de transportadores. Un transportador es utilizado internamente por $.ajaxpara realizar solicitudes. Por lo tanto, supongo que debería poder llamar $.ajaxcomo de costumbre. $.ajaxPuede encontrar información sobre transportadores y extensiones aquí .

Además, una versión quizás mejor de este complemento se puede encontrar aquí .

Otras dos notas:

  1. El objeto XDomainRequest se introdujo desde IE8 y no funcionará en las siguientes versiones.
  2. Desde IE10 CORS se admitirá utilizando un XMLHttpRequest normal .

Edición 2: problema de http a https

Las solicitudes deben estar dirigidas al mismo esquema que la página de alojamiento

Esta restricción significa que si su página AJAX está en http://example.com , su URL de destino también debe comenzar con HTTP. Del mismo modo, si su página AJAX está en https://example.com , su URL de destino también debe comenzar con HTTPS.

Fuente: http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

dennisg
fuente
12
La "mejor versión" del complemento es innata; Lo acabo de incluir en mi página y reparó automáticamente mis llamadas $ .ajax :) Suponiendo, por supuesto, que tiene todos los encabezados necesarios en su lugar.
Kato
55
Para agregar a la respuesta dennisg, xdr.js tiene un error: la devolución de llamada ajaxTransport no se invocará tal cual. Tuve que cambiarlo de acuerdo con stackoverflow.com/questions/12481560/… (se agregó "+ *" como primer argumento de la llamada ajaxTransport).
Volodymyr Otryshko
44
jQuery.XDomainRequest.js se asegura de que la página actual y la página remota sean http o https. ¿Esto significa que no puede realizar una llamada a una API https desde una página http?
Aaron
2
Vale la pena señalar que el código que estaba vinculado a moonscripts github repo es una versión antigua que no funciona. Asegúrese de obtener la última versión en: raw.github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest/…
Clintm
3
@Aaron, agregando al comentario de @ HariKaramSingh: cambiar los protocolos ( httpa https), los dominios ( google.coma bing.com), los subdominios ( mail.google.coma maps.google.com) o los protocolos ( google.com:80- el puerto predeterminado a google.com:8080) activarán una solicitud de "dominio cruzado". Básicamente todo antes del primero /en su URL debe ser idéntico.
Allicarn
62

Partiendo de la respuesta aceptada por @dennisg, logré esto con éxito usando jQuery.XDomainRequest.js de MoonScript.

El siguiente código funcionó correctamente en Chrome, Firefox e IE10, pero falló en IE9. Simplemente incluí el script y ahora funciona automáticamente en IE9. (Y probablemente 8, pero no lo he probado).

var displayTweets = function () {
    $.ajax({
        cache: false,
        type: 'GET',
        crossDomain: true,
        url: Site.config().apiRoot + '/Api/GetTwitterFeed',
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        success: function (data) {
            for (var tweet in data) {
                displayTweet(data[tweet]);
            }
        }
    });
};
JackMorrissey
fuente
3
¡El complemento jQuery.XDomainRequest.js era exactamente lo que necesitaba! No pude hacer que el complemento iexhr.js funcione para solicitudes detrás de la autenticación básica HTTP, ¡pero XDomainRequest funcionó de maravilla!
James Ford
Esto funcionó para mí. No necesitaba Site.config (). ApiRoot + (que supongo que es para Twitter ...) Pero funciona muy bien, gracias por hacerlo.
Nicholas Decker
@NicholasDecker Site.config (). ApiRoot era solo un código específico de implementación para obtener la URL raíz de la API, nada universal o elegante. Me alegro de que haya ayudado!
JackMorrissey
Esperaba que esto funcionara para mí, pero estoy tratando de PUBLICAR. Me pregunto si ese es el problema para mí.
Jack Marchetti
1
@cracker ¿Solo tienes problemas con POST? Verifique que el script se esté cargando después de jQuery y su llamada coincida con la documentación de MoonScript.
JackMorrissey
16

Puede encontrar instrucciones completas sobre cómo hacerlo utilizando el complemento "jQuery-ajaxTransport-XDomainRequest" aquí: https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest#instructions

Este complemento es activamente compatible y maneja HTML, JSON y XML. El archivo también está alojado en CDNJS, por lo que puede colocar directamente el script en su página sin configuración adicional: http://cdnjs.cloudflare.com/ajax/libs/jquery-ajaxtransport-xdomainrequest/1.0.1/jquery.xdomainrequest .min.js

MoonScript
fuente
1
Esto funcionó muy bien: caída en la solución. Increíble que este problema exista en jQuery pero ... ¡Gracias!
Cymen
3

El problema es que IE9 y versiones posteriores no son compatibles con CORS. XDomainRequest solo admite GET / POST y el text/plaintipo conten como se describe aquí: http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

Entonces, si desea usar todos los verbos HTTP y / o json, etc., debe usar otra solución. He escrito un proxy que se rebajará a proxy si se usa IE9 o menos. No tiene que cambiar su código en absoluto si está utilizando ASP.NET.

La solución está en dos partes. El primero es un script jquery que se engancha en el procesamiento jQuery ajax. Llamará automáticamente al servidor web si se realiza una solicitud crossDomain y el navegador es IE:

$.ajaxPrefilter(function (options, originalOptions, jqXhr) {
    if (!window.CorsProxyUrl) {
        window.CorsProxyUrl = '/corsproxy/';
    }
    // only proxy those requests
    // that are marked as crossDomain requests.
    if (!options.crossDomain) {
        return;
    }

    if (getIeVersion() && getIeVersion() < 10) {
        var url = options.url;
        options.beforeSend = function (request) {
            request.setRequestHeader("X-CorsProxy-Url", url);
        };
        options.url = window.CorsProxyUrl;
        options.crossDomain = false;
    }
});

En su servidor web, debe recibir la solicitud, obtener el valor del encabezado http X-CorsProxy-Url y hacer una solicitud HTTP y finalmente devolver el resultado.

Mi publicación de blog: http://blog.gauffin.org/2014/04/how-to-use-cors-requests-in-internet-explorer-9-and-below/

jgauffin
fuente
1

Acabo de hacer todas las solicitudes JSONP porque era la única solución para todos nuestros navegadores compatibles (IE7 + y los habituales). Eso sí, su respuesta técnicamente funciona para IE9, por lo que tiene la respuesta correcta.

Garrett
fuente
2
Solo una nota para cualquier persona con este problema: en este caso, si tiene un requisito <= IE7 y no tiene control sobre el servidor (por ejemplo, no puede hacer que admita etiquetas de script GET + con JSONP) su La mejor opción es un servidor de middleware liviano que traduzca la llamada JSONP a un POST y transmita la respuesta del servidor de caja negra al usuario.
mikermcneil
0

Para resolver este problema, también verifique si tiene algunos .js incluidos en su archivo ajax llamado: Recibí un error de acceso denegado al incluir shadowbox.js en mi ajax.php

hacklover
fuente
0

Estaba probando un servicio web CORS en mi máquina de desarrollo y recibía el mensaje de error "Acceso denegado" solo en IE. Firefox y Chrome funcionaron bien. ¡Resulta que esto fue causado por mi uso de localhost en la llamada ajax! Entonces, la URL de mi navegador era algo así como:

http: //my_computer.my_domain.local/CORS_Service/test.html

y mi llamada ajax dentro de test.html fue algo así como:

//fails in IE 
$.ajax({
  url: "http://localhost/CORS_Service/api/Controller",
  ...
});

Todo funcionó una vez que cambié la llamada ajax para usar la IP de mi computadora en lugar de localhost.

//Works in IE
$.ajax({
  url: "http://192.168.0.1/CORS_Service/api/Controller",
  ...
});

La pestaña "Red" de la ventana de herramientas de desarrollo de IE también muestra la solicitud de OPCIONES de verificación previa de CORS seguida de XMLHttpRequest GET, que es exactamente lo que esperaba ver.

jwill212
fuente
-1

Nota - Nota

no use " http://www.domain.xxx " o " http: // localhost / " o "IP >> 127.0.0.1" para URL en ajax. solo use la ruta (directorio) y el nombre de la página sin dirección.

estado falso:

var AJAXobj = createAjax();
AJAXobj.onreadystatechange = handlesAJAXcheck;
AJAXobj.open('POST', 'http://www.example.com/dir/getSecurityCode.php', true);
AJAXobj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
AJAXobj.send(pack);

estado verdadero:

var AJAXobj = createAjax();
AJAXobj.onreadystatechange = handlesAJAXcheck;
AJAXobj.open('POST', 'dir/getSecurityCode.php', true);   // <<--- note
AJAXobj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
AJAXobj.send(pack);
Ali Bagheri
fuente