IE9 jQuery AJAX com CORS retorna "Acesso negado"

123

O seguinte funciona em todos os navegadores, exceto no IE (estou testando no 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'
            }
        );

Eu tenho outra função que usa dataType: 'jsonp', mas não preciso de nenhum dado retornado nessa chamada AJAX. Meu último recurso será retornar algumas bobagens envoltas em JSONP apenas para fazê-lo funcionar.

Alguma idéia de por que o IE está estragando uma solicitação CORS que não retorna dados?

Garrett
fonte
Como nenhuma das respostas propostas funcionou para mim (eu também tive que passar cookies na solicitação do CORS, o que é um não-não ao usar o XDomainRequest), aqui está uma solução alternativa : blog.gauffin.org/2014/04/… . Proxying para o resgate! : p
wimvds 28/05

Respostas:

150

Este é um bug conhecido do jQuery. A equipe do jQuery "não tem planos de suportar isso no núcleo e é mais adequada como um plug-in". (Veja este comentário ). O IE não usa o XMLHttpRequest , mas um objeto alternativo chamado XDomainRequest .

Não é um plugin disponível para apoiar isso em jQuery, que pode ser encontrada aqui : https://github.com/jaubourg/ajaxHooks/blob/master/src/xdr.js

EDIT A função $.ajaxTransportregistra uma fábrica de transportadores. Um transportador é usado internamente pelo $.ajaxpara executar solicitações. Portanto, suponho que você consiga ligar $.ajaxnormalmente. Informações sobre transportadores e extensão $.ajaxpodem ser encontradas aqui .

Além disso, uma versão talvez melhor deste plugin pode ser encontrada aqui .

Duas outras notas:

  1. O objeto XDomainRequest foi introduzido no IE8 e não funcionará nas versões abaixo.
  2. No IE10, o CORS será suportado usando um XMLHttpRequest normal .

Editar 2: problema de http para https

As solicitações devem ser direcionadas para o mesmo esquema da página de hospedagem

Essa restrição significa que, se sua página AJAX estiver em http://example.com , o URL de destino também deverá começar com HTTP. Da mesma forma, se sua página AJAX estiver em https://example.com , o URL de destino também deverá começar com HTTPS.

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

dennisg
fonte
12
A "versão melhor" do plugin é inata; Acabei de incluí-lo na minha página e corrigiu automaticamente minhas chamadas de $ .ajax :) Supondo, é claro, que você tenha todos os cabeçalhos necessários .
Kato
5
Para adicionar à resposta dennisg, o xdr.js possui um erro - o retorno de chamada ajaxTransport não será chamado como está. Eu tive que alterá-lo de acordo com stackoverflow.com/questions/12481560/… (adicionado "+ *" como o primeiro argumento da chamada ajaxTransport).
Volodymyr Otryshko
4
O jQuery.XDomainRequest.js garante que a página atual e a remota sejam http ou https. Isso significa que você não pode fazer uma chamada para uma API https a partir de uma página http?
Aaron
2
Vale a pena notar que o código que estava vinculado ao moonscripts github repo é uma versão antiga que não funciona. Certifique-se de obter a versão mais recente em: raw.github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest/…
Clintm
3
@Aaron, acrescentando ao comentário do @ HariKaramSingh: alterar protocolos ( httppara https), domínios ( google.compara bing.com), subdomínios ( mail.google.compara maps.google.com) ou protocolos ( google.com:80- a porta padrão para google.com:8080) acionará uma solicitação de "domínio cruzado". Basicamente, tudo o que precede o primeiro /no seu URL precisa ser idêntico.
Allicarn 31/05
62

Com base na resposta aceita por @dennisg, consegui isso com sucesso usando jQuery.XDomainRequest.js do MoonScript.

O código a seguir funcionou corretamente no Chrome, Firefox e IE10, mas falhou no IE9. Simplesmente incluí o script e agora funciona automaticamente no IE9. (E provavelmente 8, mas ainda não testei.)

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
fonte
3
O plugin jQuery.XDomainRequest.js era exatamente o que eu precisava! Não consegui que o plugin iexhr.js funcionasse para solicitações por trás da autenticação básica HTTP, mas o XDomainRequest funcionou como um encanto!
James Ford
Isso funcionou para mim. Eu não precisava do Site.config (). ApiRoot + (que eu suponho que seja para o twitter ....) Mas funciona muito bem, obrigado por fazer isso.
Nicholas Decker
@NicholasDecker Site.config (). ApiRoot era apenas um código específico de implementação para obter o URL raiz da API, nada universal ou sofisticado. Fico feliz que ajudou!
JackMorrissey
Eu esperava que isso funcionasse para mim, mas estou tentando postar. me pergunto se esse é o problema para mim.
21313 Jack Marchetti
1
@ cracker Você está tendo problemas apenas com o POST? Verifique novamente se o script está carregando após o jQuery e se sua chamada corresponde à documentação do MoonScript.
JackMorrissey
16

Instruções completas sobre como fazer isso usando o plug-in "jQuery-ajaxTransport-XDomainRequest" podem ser encontradas aqui: https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest#instructions

Este plugin é suportado ativamente e lida com HTML, JSON e XML. O arquivo também está hospedado no CDNJS, para que você possa soltar diretamente o script em sua página sem nenhuma configuração adicional: http://cdnjs.cloudflare.com/ajax/libs/jquery-ajaxtransport-xdomainrequest/1.0.1/jquery.xdomainrequest .min.js

MoonScript
fonte
1
Isso funcionou muito bem - queda na correção. Inacreditável que esse problema exista no jQuery, mas ... Obrigado!
Cymen
3

O problema é que o IE9 e abaixo não suportam o CORS. O XDomainRequest suporta apenas GET / POST e o text/plaintipo de conteúdo, conforme descrito aqui: http://blogs.msdn.com/b/ieinternals/archive/2010/05/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

Portanto, se você quiser usar todos os verbos HTTP e / ou json, etc, precisará usar outra solução. Eu escrevi um proxy que fará o downgrade para proxy se o IE9 ou menos for usado. Você não precisa alterar seu código se estiver usando o ASP.NET.

A solução está em duas partes. O primeiro é um script jquery que se conecta ao processamento ajax do jQuery. Ele chamará automaticamente o servidor da Web se uma solicitação crossDomain for feita e o navegador for 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;
    }
});

No servidor da web, você precisa receber a solicitação, obter o valor do cabeçalho http X-CorsProxy-Url e fazer uma solicitação HTTP e, finalmente, retornar o resultado.

Minha postagem no blog: http://blog.gauffin.org/2014/04/how-to-use-cors-requests-in-internet-explorer-9-and-below/

jgauffin
fonte
1

Acabei de fazer todos os pedidos JSONP, porque era a única solução para todos os nossos navegadores suportados (IE7 + e regulares). Lembre-se, sua resposta tecnicamente funciona para o IE9, para que você tenha a resposta correta.

Garrett
fonte
2
Apenas uma observação para qualquer pessoa com esse problema - nesse caso, se você tiver um requisito <= IE7 e não tiver controle sobre o servidor (por exemplo, não pode fazê-lo suportar tags de script GET + com JSONP), sua A melhor aposta é um servidor de middleware leve que converte a chamada JSONP em um POST e transmite a resposta do servidor de caixa preta de volta ao usuário.
Mckmcneil
1

Com base na solução do MoonScript, você pode tentar isso:

https://github.com/intuit/xhr-xdr-adapter/blob/master/src/xhr-xdr-adapter.js

O benefício é que, como é uma solução de nível inferior, ele habilita o CORS (na medida do possível) no IE 8/9 com outras estruturas, não apenas com o jQuery. Eu tive sucesso usando-o com o AngularJS, assim como o jQuery 1.xe 2.x.

Yanni
fonte
0

Para resolver esse problema, verifique também se você incluiu alguns .js no arquivo ajax chamado: Recebi erro de acesso negado ao incluir shadowbox.js no meu ajax.php

hacklover
fonte
0

Eu estava testando um serviço da web CORS na minha máquina de desenvolvimento e estava recebendo a mensagem de erro "Acesso negado" apenas no IE. Firefox e Chrome funcionaram bem. Acontece que isso foi causado pelo uso do host local na chamada ajax! Portanto, o URL do meu navegador era algo como:

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

e minha chamada ajax dentro do test.html era algo como:

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

Tudo funcionou depois que eu mudei a chamada ajax para usar o IP do meu computador em vez do localhost.

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

A guia "Rede" da janela de ferramentas de desenvolvimento do IE também mostra a solicitação CORS Preflight OPTIONS seguida pelo XMLHttpRequest GET, que é exatamente o que eu esperava ver.

jwill212
fonte
0

Atualize a partir do início de 2015. O xDomain é uma biblioteca amplamente usada para suportar o CORS no IE9 com codificação extra limitada.

https://github.com/jpillora/xdomain

Bernard
fonte
-1

Nota - Nota

não use " http://www.domain.xxx " ou " http: // localhost / " ou "IP >> 127.0.0.1" para URL no ajax. use somente o caminho (diretório) e o nome da página sem endereço.

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);

verdadeiro estado:

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
fonte