简体   繁体   English

为什么有些跨域JSON请求失败,而另一些却没有?

[英]Why do some cross-domain JSON-requests fail but others don't?

I have a little trouble understanding the security bit around JSON, because often things that in theory should not work, seemingly do. 我在理解围绕JSON的安全性方面遇到了一些麻烦,因为从理论上讲似乎不起作用的事情通常看起来似乎是可行的。 AFAIK, calls from a script on a page that resides on domain A, are not supposed to be able receive data from a domain B. But in the code below the calls to one external domain fail, whereas another goes through. AFAIK(来自位于域A上的页面上的脚本的调用)不应从域B接收数据。但是在下面的代码中,对一个外部域的调用失败,而对另一个外部域的调用失败。 And neither one are packed JSON calls (jsonp). 而且没有人打包JSON调用(jsonp)。

Why is this? 为什么是这样? Should not both be disallowed from getting through the browser security checks? 难道不应该都禁止浏览器进行安全检查吗? I get the same results in Chrome and Firefox. 我在Chrome和Firefox中得到了相同的结果。 If I host the below html-page on dropbox.com, Chrome gives me this error message: 如果我在dropbox.com上托管以下html页面,Chrome会显示以下错误消息:

XMLHttpRequest cannot load http://www.odinfond.no/rest/fund/calc/fundReturn?&id=300&oneTimeInvestment=100000&oneTimeInvestmentDate=2009-11-01&endDate=2010-11-01&currency=NOK . XMLHttpRequest无法加载http://www.odinfond.no/rest/fund/calc/fundReturn?&id=300&oneTimeInvestment=100000&oneTimeInvestmentDate=2009-11-01&endDate=2010-11-01&currency=NOK Origin http://dl.dropbox.com is not allowed by Access-Control-Allow-Origin. Access-Control-Allow-Origin不允许使用来源http://dl.dropbox.com

The JSON response I would have gotten if the call went through can be seen by clicking this direct link . 通过单击此直接链接,可以看到如果呼叫通过我将得到的JSON响应。 The call to the other service returns successfully. 对其他服务的调用成功返回。 I host the below code on 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>

You'll notice that the working request has a response header: 您会注意到工作请求有一个响应头:

Access-Control-Allow-Origin: *

This is what frees up the browser to make the response available to the script. 这就是释放浏览器以使响应可用于脚本的原因。 (Note that the request is always made, the same origin policy only affects whether the response is accessible to the script or not) (请注意, 始终会发出请求,相同的原始策略只会影响脚本是否可以访问响应)

If the '*' is a hostname, access is only allowed if the current document's hostname matches the Access-Control-Allow-Origin header 如果“ *”是主机名,则仅当当前文档的主机名与Access-Control-Allow-Origin标头匹配时才允许Access-Control-Allow-Origin

Browsing the source code , it appears that $.ajax() detects remote URLs and replaces AJAX (XMLHttpRequest ) with good old script tags: 浏览源代码时 ,似乎$ .ajax()检测到远程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;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM