2010-11-18 46 views
5

我对JSON周围的安全位理解有点麻烦,因为通常理论上不应该这样做的东西看起来确实如此。 AFAIK,来自驻留在域A上的页面上的脚本的调用不应该能够从域B接收数据。但是,在下面的代码中,对一个外部域的调用失败,而另一个经历。没有人打包JSON调用(jsonp)。为什么某些跨域JSON请求失败,但其他却不行?

这是为什么?不应该都不能通过浏览器安全检查吗?我在Chrome和Firefox中获得了相同的结果。如果我主办dropbox.com下面的HTML页面,浏览器给了我此错误消息:

的XMLHttpRequest无法加载 http://www.odinfond.no/rest/fund/calc/fundReturn?&id=300&oneTimeInvestment=100000&oneTimeInvestmentDate=2009-11-01&endDate=2010-11-01&currency=NOK。 来源http://dl.dropbox.com不是 允许通过 访问控制允许来源。

通过点击this direct link可以看到如果通话已经通过,我会得到的JSON响应。对其他服务的调用成功返回。我在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> 

回答

6

你会发现,工作要求有一个响应头:

Access-Control-Allow-Origin: * 

这是解放了的浏览器,以提供给脚本的响应。 (请注意,请求始终为,相同的原始策略仅影响脚本是否可以访问该响应)

如果'*'是主机名,则只有在当前文档的主机名匹配Access-Control-Allow-Origin

+0

谢谢,这非常有意义!我认为这些请求几乎完全相同,但是我从来没有注意到响应头中的区别:-) – oligofren 2010-11-18 22:13:25

0

浏览source code,似乎$。阿贾克斯()检测远程URL,并取代AJAX(XMLHttpRequest的 )具有良好的旧脚本标签:

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

该片段的第一行显示,只有当您将{dataType:“script”}传入AJAX调用 – Gareth 2010-11-18 22:06:14

+0

我添加了一个更早的摘录,其中's.dataType'的值被更改。 – 2010-11-18 22:13:07

相关问题