2010-11-18 19 views
5

Tengo un pequeño problema para entender el bit de seguridad de JSON, porque a menudo cosas que, en teoría, no deberían funcionar, al parecer sí. AFAIK, las llamadas de una secuencia de comandos en una página que reside en el dominio A, no se supone que pueden recibir datos de un dominio B. Pero en el código a continuación las llamadas a un dominio externo fallan, mientras que otro pasa. Y ninguno de los dos está lleno de llamadas JSON (jsonp).¿Por qué algunas solicitudes JSON entre dominios fallan pero otras no?

¿Por qué es esto? ¿No se debería prohibir que ambos pasen por las comprobaciones de seguridad del navegador? Obtengo los mismos resultados en Chrome y Firefox. Si el anfitrión de la página HTML de abajo en dropbox.com, Chrome me da este mensaje de error:

XMLHttpRequest no puede cargar http://www.odinfond.no/rest/fund/calc/fundReturn?&id=300&oneTimeInvestment=100000&oneTimeInvestmentDate=2009-11-01&endDate=2010-11-01&currency=NOK. Origen http://dl.dropbox.com no es permitido por Access-Control-Allow-Origin.

La respuesta JSON que habría obtenido si la llamada se hubiera podido ver se puede ver haciendo clic en this direct link. La llamada al otro servicio vuelve con éxito. Tengo el código siguiente en Dropbox. Try it out here.

<!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> 

Respuesta

6

Se dará cuenta de que la solicitud de trabajo tiene un encabezado de respuesta:

Access-Control-Allow-Origin: * 

Esto es lo que libera el navegador para que la respuesta a disposición del guión. (Tenga en cuenta que la solicitud es siempre hecho, la misma política de origen sólo afecta si la respuesta es accesible a la secuencia de comandos o no)

Si el '*' es un nombre de host, el acceso sólo se permite si el nombre de host del documento actual coincide con la cabecera Access-Control-Allow-Origin

+0

Gracias, eso tiene mucho sentido! Pensé que las solicitudes eran casi idénticas, pero nunca noté la diferencia en el encabezado de respuesta :-) – oligofren

0

Navegar por source code, parece que .ajax $() detecta URLs remotas y reemplaza AJAX (XMLHttpRequest ) con buenas etiquetas script de edad:

// 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; 
    } 
+0

La primera línea de ese fragmento muestra que esto solo ocurre específicamente cuando pasa {dataType: "script"} a la llamada AJAX – Gareth

+0

He agregado un extracto anterior, donde se cambia el valor de 's.dataType'. –

Cuestiones relacionadas