domínio cruzado AJAX do jQuery

477

Aqui estão duas páginas, test.php e testserver.php.

test.php

<script src="scripts/jq.js" type="text/javascript"></script>
<script>
    $(function() {
        $.ajax({url:"testserver.php",
            success:function() {
                alert("Success");
            },
            error:function() {
                alert("Error");
            },
            dataType:"json",
            type:"get"
        }
    )})
</script>

testserver.php

<?php
$arr = array("element1",
             "element2",
             array("element31","element32"));
$arr['name'] = "response";
echo json_encode($arr);
?>

Agora, meu problema: quando esses dois arquivos estão no mesmo servidor (localhost ou servidor web), ele funciona e alert("Success")é chamado; Se estiver em servidores diferentes, o que significa testingerver.php no servidor web e test.php no host local, não está funcionando e alert("Error")está em execução. Mesmo que o URL dentro do ajax seja alterado para http://domain.com/path/to/file/testserver.php

Firose Hussain
fonte
38
Para as pessoas que estão por aqui. Leia este para ter uma idéia de como cruz javascript domínio chama trabalho stackoverflow.com/a/11736771/228656
Abdul Munim
1
Eu escrevi uma resposta para esta pergunta aqui: Carregando página html domínio cruzado com jQuery AJAX - o último, suportes https
jherax

Respostas:

412

Use JSONP .

jQuery:

$.ajax({
     url:"testserver.php",
     dataType: 'jsonp', // Notice! JSONP <-- P (lowercase)
     success:function(json){
         // do stuff with json (in this case an array)
         alert("Success");
     },
     error:function(){
         alert("Error");
     }      
});

PHP:

<?php
$arr = array("element1","element2",array("element31","element32"));
$arr['name'] = "response";
echo $_GET['callback']."(".json_encode($arr).");";
?>

O eco pode estar errado, já faz um tempo desde que eu usei o php. Em qualquer caso, você precisa emitir callbackName('jsonString')as cotações. O jQuery passará seu próprio nome de retorno de chamada, portanto você precisa obtê-lo dos parâmetros GET.

E como Stefan Kendall postou, $ .getJSON () é um método abreviado, mas você precisa anexar 'callback=?'ao URL como parâmetro GET (sim, o valor é?, O jQuery substitui isso por seu próprio método de retorno de chamada gerado).

BGerrissen
fonte
2
Por que você precisa retornar em callbackName('/* json */')vez de callbackName(/* json */)?
Eric
3
@eric, o retorno de chamada espera uma string JSON. Teoricamente, um objeto também pode funcionar, mas não tem certeza de como o jQuery responde a isso, pode gerar um erro ou falhar silenciosamente.
BGerrissen
Estou recebendo o seguinte erro. Erro de sintaxe: ausente; antes da instrução {"ResultCode": 2}. Onde {"ResultCode": 2} é a resposta. Conselho por favor.
user2003356
@ user2003356 parece que você está retornando JSON simples em vez de JSONP. Você precisa retornar algo como: callbackFunction ({"ResultCode": 2}). O jQuery adiciona o parâmetro GET 'callback' à solicitação, esse é o nome da função de retorno de chamada que o jquery usa e deve ser adicionado à resposta.
BGerrissen
2
É 2016. O CORS agora é um padrão amplamente suportado, em oposição ao JSONP, que só pode ser descrito como um hack. A resposta de @ joshuarh abaixo deve ser a preferida agora.
Vicky Chijwani
202

JSONP é uma boa opção, mas existe uma maneira mais fácil. Você pode simplesmente definir o Access-Control-Allow-Origincabeçalho no seu servidor. A configuração para *aceitar solicitações AJAX entre domínios de qualquer domínio. ( https://developer.mozilla.org/en/http_access_control )

O método para fazer isso varia de idioma para idioma, é claro. Aqui está no Rails:

class HelloController < ApplicationController
  def say_hello
    headers['Access-Control-Allow-Origin'] = "*"
    render text: "hello!"
  end
end

Neste exemplo, a say_helloação aceitará solicitações AJAX de qualquer domínio e retornará uma resposta "Olá!".

Aqui está um exemplo dos cabeçalhos que podem retornar:

HTTP/1.1 200 OK 
Access-Control-Allow-Origin: *
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: text/html; charset=utf-8
X-Ua-Compatible: IE=Edge
Etag: "c4ca4238a0b923820dcc509a6f75849b"
X-Runtime: 0.913606
Content-Length: 6
Server: WEBrick/1.3.1 (Ruby/1.9.2/2011-07-09)
Date: Thu, 01 Mar 2012 20:44:28 GMT
Connection: Keep-Alive

Por mais fácil que seja, ele tem algumas limitações no navegador. Consulte http://caniuse.com/#feat=cors .

Joshuarh
fonte
12
Jsonp não suportava postar, colocar e excluir. Sua solução funciona muito bem.
21412 TonyTakeshi
35
no cabeçalho do PHP ("Access-Control-Allow-Origin: *");
SparK
9
@Warrior Se você estiver usando o .post()método jQuery, precisará ativar o suporte entre domínios no jQuery. É feito com isto: $.support.cors = true.
precisa
21
Quais são as implicações de segurança da configuração de um servidor dessa maneira?
Jon Schneider
19
Seria melhor permitir apenas os domínios com os quais você deseja compartilhar os dados, em vez de usar o wilcard "*".
Sebastián Grignoli
32

Você pode controlar isso via cabeçalho HTTP adicionando Access-Control-Allow-Origin . A configuração como * aceitará solicitações AJAX entre domínios de qualquer domínio.

Usando o PHP é muito simples, basta adicionar a seguinte linha ao script que você deseja acessar fora do seu domínio:

header("Access-Control-Allow-Origin: *");

Não se esqueça de ativar o módulo mod_headers no httpd.conf.

Adorjan Princz
fonte
você salvou meu dia.
NomanJaved
20

Você precisa dar uma olhada na mesma política de origem :

Na computação, a mesma política de origem é um conceito de segurança importante para várias linguagens de programação do navegador, como JavaScript. A política permite que scripts em execução nas páginas originárias do mesmo site acessem os métodos e propriedades um do outro sem restrições específicas, mas impede o acesso à maioria dos métodos e propriedades nas páginas de sites diferentes.

Para que você possa obter dados, é necessário:

Mesmo protocolo e host

Você precisa implementar o JSONP para contorná -lo.

Sarfraz
fonte
17

Eu tive que carregar a página do disco local "file: /// C: /test/htmlpage.html", chamar "URL http: //localhost/getxml.php" e fazer isso nos navegadores IE8 + e Firefox12 +, use o jQuery v1 .7.2 lib para minimizar o código padrão. Depois de ler dezenas de artigos, finalmente entendi. Aqui está o meu resumo.

  • O script do servidor (.php, .jsp, ...) deve retornar o cabeçalho de resposta http Access-Control-Allow-Origin: *
  • antes de usar o jQuery ajax, defina esse sinalizador em javascript: jQuery.support.cors = true;
  • você pode definir o sinalizador uma vez ou todas as vezes antes de usar a função jQuery ajax
  • agora eu posso ler o documento .xml no IE e Firefox. Outros navegadores que não testei.
  • O documento de resposta pode ser sem formatação / texto, xml, json ou qualquer outra coisa

Aqui está um exemplo de chamada ajax do jQuery com alguns sysouts de depuração.

jQuery.support.cors = true;
$.ajax({
    url: "http://localhost/getxml.php",
    data: { "id":"doc1", "rows":"100" },
    type: "GET",
    timeout: 30000,
    dataType: "text", // "xml", "json"
    success: function(data) {
        // show text reply as-is (debug)
        alert(data);

        // show xml field values (debug)
        //alert( $(data).find("title").text() );

        // loop JSON array (debug)
        //var str="";
        //$.each(data.items, function(i,item) {
        //  str += item.title + "\n";
        //});
        //alert(str);
    },
    error: function(jqXHR, textStatus, ex) {
        alert(textStatus + "," + ex + "," + jqXHR.responseText);
    }
});
Quem eu
fonte
1
Eu escrevi uma resposta para esta pergunta aqui: Carregando página html domínio cruzado com jQuery AJAX - o último, suportes https
jherax
Para o ponto mais importante: no PHP, adicione esta linha ao script:header("Access-Control-Allow-Origin: *");
T30
1
@whome muito obrigado pela sua resposta. Você me ajudou muito. Felicidades.
Luis Milanese
10

É verdade que a política de mesma origem impede que o JavaScript faça solicitações entre domínios, mas a especificação CORS permite exatamente o tipo de acesso à API que você está procurando e é suportada pelo lote atual dos principais navegadores.

Veja como habilitar o compartilhamento de recursos de origem cruzada para cliente e servidor:

http://enable-cors.org/

"O CORS (compartilhamento de recursos de origem cruzada) é uma especificação que permite acesso verdadeiramente aberto através dos limites do domínio. Se você exibir conteúdo público, considere usar o CORS para abri-lo para acesso universal a JavaScript / navegador".

Jason
fonte
9

Eu uso o servidor Apache, então usei o módulo mod_proxy. Ativar módulos:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

Adicione então:

ProxyPass /your-proxy-url/ http://service-url:serviceport/

Por fim, passe o proxy-url para o seu script.

zenio
fonte
8

A segurança do navegador impede fazer uma chamada ajax de uma página hospedada em um domínio para uma página hospedada em um domínio diferente; isso é chamado de " política de mesma origem ".

Jacob Mattison
fonte
4

Nos documentos do Jquery ( link ):

  • Devido a restrições de segurança do navegador, a maioria das solicitações "Ajax" está sujeita à mesma política de origem; a solicitação não pode recuperar dados de um domínio, subdomínio ou protocolo diferente.

  • As solicitações de script e JSONP não estão sujeitas às mesmas restrições de política de origem.

Então, eu presumo que você precisa usar o jsonp para a solicitação. Mas não tentei isso sozinho.

William Clemens
fonte
2

Conheço três maneiras de resolver seu problema:

  1. Primeiro, se você tiver acesso aos dois domínios, poderá permitir o acesso a todos os outros domínios usando:

    header("Access-Control-Allow-Origin: *");

    ou apenas um domínio adicionando o código abaixo ao arquivo .htaccess:

    <FilesMatch "\.(ttf|otf|eot|woff)$"> <IfModule mod_headers.c> SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.net|dev02.otherdomain.net)$" AccessControlAllowOrigin=$0 Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin </IfModule> </FilesMatch>

  2. você pode ter uma solicitação ajax para um arquivo php no seu servidor e manipular a solicitação para outro domínio usando esse arquivo php.

  3. você pode usar o jsonp, porque ele não precisa de permissão. para isso, você pode ler a resposta do nosso amigo @BGerrissen.
Ali_Hr
fonte
0

Para o Microsoft Azure, é um pouco diferente.

O Azure tem uma configuração especial do CORS que precisa ser definida. É essencialmente a mesma coisa nos bastidores, mas simplesmente definir o cabeçalho que joshuarh menciona não funcionará. A documentação do Azure para habilitar vários domínios pode ser encontrada aqui:

https://docs.microsoft.com/en-us/azure/app-service-api/app-service-api-cors-consume-javascript

Eu brinquei com isso por algumas horas antes de perceber que minha plataforma de hospedagem tinha essa configuração especial.

Josh Schultz
fonte
0

funciona, tudo que você precisa:

PHP:

header('Access-Control-Allow-Origin: http://www.example.com');
header("Access-Control-Allow-Credentials: true");
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');

JS (jQuery ajax):

var getWBody = $.ajax({ cache: false,
        url: URL,
        dataType : 'json',
        type: 'GET',
        xhrFields: { withCredentials: true }
});
Paun Narcis Iulian
fonte