为什么某些跨域JSON请求失败,但其他却不行?
我对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¤cy=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>
你会发现,工作要求有一个响应头:
Access-Control-Allow-Origin: *
这是解放了的浏览器,以提供给脚本的响应。 (请注意,请求始终为,相同的原始策略仅影响脚本是否可以访问该响应)
如果'*'是主机名,则只有在当前文档的主机名匹配Access-Control-Allow-Origin
头
浏览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;
}
该片段的第一行显示,只有当您将{dataType:“script”}传入AJAX调用 – Gareth 2010-11-18 22:06:14
我添加了一个更早的摘录,其中's.dataType'的值被更改。 – 2010-11-18 22:13:07
谢谢,这非常有意义!我认为这些请求几乎完全相同,但是我从来没有注意到响应头中的区别:-) – oligofren 2010-11-18 22:13:25