2010-11-18 18 views
5

Ho un po 'di problemi a capire il bit di sicurezza attorno a JSON, perché spesso cose che in teoria non dovrebbero funzionare, apparentemente lo fanno. AFAIK, le chiamate da uno script su una pagina che risiede sul dominio A, non dovrebbero essere in grado di ricevere dati da un dominio B. Ma nel codice sottostante le chiamate a un dominio esterno falliscono, mentre un altro passa attraverso. E nessuno dei due è pieno di chiamate JSON (jsonp).Perché alcune richieste JSON tra domini falliscono ma altre no?

Perché è questo? Non dovrebbero essere entrambi non autorizzati a superare i controlli di sicurezza del browser? Ottengo gli stessi risultati in Chrome e Firefox. Se io ospitare la pagina HTML in basso a dropbox.com, Chrome mi dà questo messaggio di errore:

XMLHttpRequest non può caricare http://www.odinfond.no/rest/fund/calc/fundReturn?&id=300&oneTimeInvestment=100000&oneTimeInvestmentDate=2009-11-01&endDate=2010-11-01&currency=NOK. L'origine http://dl.dropbox.com non è consentita da Access-Control-Allow-Origin.

La risposta JSON che avrei ottenuto se la chiamata è passata può essere vista facendo clic su this direct link. La chiamata all'altro servizio restituisce correttamente. Ospito il seguente codice su 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> 

risposta

6

Si noterà che la richiesta di lavoro ha un'intestazione di risposta:

Access-Control-Allow-Origin: * 

Questo è ciò che libera il browser per rendere la risposta disponibile per lo script. (Si noti che la richiesta è sempre fatto, la stessa politica di origine influisce solo se la risposta è accessibile allo script o meno)

Se il '*' è un nome host, l'accesso è consentito solo se il nome host del documento corrente corrisponde al Access-Control-Allow-Origin intestazione

+0

Grazie, ha perfettamente senso! Ho pensato che le richieste fossero quasi identiche, ma non ho mai notato la differenza nell'intestazione della risposta :-) – oligofren

0

Navigando in source code, sembra che $ .ajax() rileva URL remoti e sostituisce AJAX (XMLHttpRequest ) con buone etichette vecchio copione:

// 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 prima riga di quel frammento mostra che questo accade solo quando si passa {dataType: "script"} nella chiamata AJAX – Gareth

+0

Ho aggiunto un estratto precedente, in cui il valore di 's.dataType' viene modificato. –

Problemi correlati