Pergunta

Tenho um pouco de problemas para entender a segurança em JSON, porque muitas vezes as coisas que, em teoria não deveriam funcionar, aparentemente funcionam. Afaik, chamadas de um script em uma página que reside no domínio A, não devem poder receber dados de um domínio B. Mas no código abaixo das chamadas para um domínio externo falham, enquanto outro passa. E nenhum deles é ligue para JSON (JSONP).

Por que é isso? Ambos não devem ser exibidos por passar pelas verificações de segurança do navegador? Eu recebo os mesmos resultados em Chrome e Firefox. Se eu hospedar o HTML-página abaixo no DropBox.com, o Chrome me dará esta mensagem de erro:

XmlHttPrequest não pode carregar http://www.odinfond.no/rest/fund/calc/fundreturn?&id=300&onetimeinvestment=100000&oneTimeinvestmentdate=2009-11-01&enddate=2010-11-01äcy=nok. Origem http://dl.dropbox.com não é permitido pela Origin-Origin Access-Control.

A resposta JSON que eu teria recebido se a chamada passada pudesse ser vista clicando Este link direto. A chamada para o outro serviço retorna com sucesso. Eu hospedo o código abaixo no Dropbox. Experimente aqui.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <meta http-equiv="Content-type" content="text/html;charset=UTF-8" />

  <title>JSON/JSONP test</title>
  <script src="jquery.js" type="text/javascript"></script>
 </head>

 <body>
  <script>
   service = 'http://www.odinfond.no/rest/fund/calc/fundReturn?'; 
   parameters = { 
     id: '300',
     oneTimeInvestment:'100000',
     oneTimeInvestmentDate:'2009-11-01',
     endDate:'2010-11-01',
     currency:'NOK'
    }
   $.getJSON( service, parameters, function(data) {
    alert("Success"); 
   });

   service = 'http://ws.geonames.org/postalCodeLookupJSON?'
   parameters = {
    postalcode:1540,
    country:'NO'
   }
   $.getJSON(service, parameters, function(data) {
    alert(data.postalcodes[0].adminName2);
   });
  </script>
  <p>Use Firebug to see JSON response</p>
 </body>
</html>
Foi útil?

Solução

Você notará que o pedido de trabalho tem um cabeçalho de resposta:

Access-Control-Allow-Origin: *

É isso que libera o navegador para disponibilizar a resposta ao script. (Observe que a solicitação é sempre Feito, a mesma política de origem afeta apenas se a resposta é acessível ao script ou não)

Se o '*' for um nome de host, o acesso só será permitido se o nome do host do documento atual corresponder ao Access-Control-Allow-Origin cabeçalho

Outras dicas

Navegando no Código fonte, parece que $ .ajax () detecta URLs remotos e substitui o AJAX (xmlHttPrequest) por boas etiquetas de script antigas:

    // Build temporary JSONP function
    if ( s.dataType === "json" && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {
        jsonp = s.jsonpCallback || ("jsonp" + jsc++);

        // Replace the =? sequence both in the query string and the data
        if ( s.data ) {
            s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
        }

        s.url = s.url.replace(jsre, "=" + jsonp + "$1");

        // We need to make sure
        // that a JSONP style response is executed properly
        s.dataType = "script";

        // Handle JSONP-style loading
        var customJsonp = window[ jsonp ];

        window[ jsonp ] = function( tmp ) {
            if ( jQuery.isFunction( customJsonp ) ) {
                customJsonp( tmp );

            } else {
                // Garbage collect
                window[ jsonp ] = undefined;

                try {
                    delete window[ jsonp ];
                } catch( jsonpError ) {}
            }

            data = tmp;
            jQuery.handleSuccess( s, xhr, status, data );
            jQuery.handleComplete( s, xhr, status, data );

            if ( head ) {
                head.removeChild( script );
            }
        };
    }

[...]

    // Matches an absolute URL, and saves the domain
    var parts = rurl.exec( s.url ),
        remote = parts && (parts[1] && parts[1].toLowerCase() !== location.protocol || parts[2].toLowerCase() !== location.host);

    // If we're requesting a remote document
    // and trying to load JSON or Script with a GET
    if ( s.dataType === "script" && type === "GET" && remote ) {
        var head = document.getElementsByTagName("head")[0] || document.documentElement;
        var script = document.createElement("script");
        if ( s.scriptCharset ) {
            script.charset = s.scriptCharset;
        }
        script.src = s.url;

        // Handle Script loading
        if ( !jsonp ) {
            var done = false;

            // Attach handlers for all browsers
            script.onload = script.onreadystatechange = function() {
                if ( !done && (!this.readyState ||
                        this.readyState === "loaded" || this.readyState === "complete") ) {
                    done = true;
                    jQuery.handleSuccess( s, xhr, status, data );
                    jQuery.handleComplete( s, xhr, status, data );

                    // Handle memory leak in IE
                    script.onload = script.onreadystatechange = null;
                    if ( head && script.parentNode ) {
                        head.removeChild( script );
                    }
                }
            };
        }

        // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
        // This arises when a base node is used (#2709 and #4378).
        head.insertBefore( script, head.firstChild );

        // We handle everything using the script element injection
        return undefined;
    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top