来自《javascript高级程序设计 第三版:作者Nicholas C. Zakas》的学习笔记(十)
通过XHR实现Ajax通信的一个主要限制,来源于跨域安全策略。默认情况下,XHR对象只能访问与包含它的页面位于同一个域中的资源。这种安全策略可以预防某些恶意行为。CORS(Crossing-Orgin Resourse Sharing,跨域资源共享),定义了在必须防问跨域资源时,浏览器与服务器应该如何沟通。其背后的思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是应该失败。
IE对CORS的实现:
IE8中引入了XDR:
xhr.open("post","example.php",true);
var form = docuent.getElementById("user-infor");
xhr.send(new FormData(form)); var xdr = new XDomainRequest();
xdr.onload = function() {
alert(xdr.responseText);
};
xdr.onerror = function() {
alert("An error");
};
xdr.open(....);
xdr.contentType = "...";
xdr.send(...);
其它浏览器对CORS的实现:
都是通过XMLHttpRequest对象实现对CORS的原生支持。尝试打开不同来源的资源的时候,无需额外编写代码就可以出发这个行为。要请求位于另一个域中资源,使用标准的XHR对象并在open()方法传入绝对URL即可。
为了安全,有以下限制:
① 不能使用setRequestHeader()设置自定义头部;
② 不能发送和接受cookie;
③ 调用getAllResponseHeaders()方法总会返回空字符串。
跨浏览器的CORS
检测XHR是否支持CORS的最简单方式,就是检查是否存在withCredentials属性。再结合检测XDomianRequest对象是否存在,就可以兼顾所有浏览器了。
function createCORSRequest(method,url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
xhr.open();
}else if (typeof XDomianRequest != "undefined") {
vxhr = new XDomainRequest(method,url);
vxhr.open(method,url);
}else {
xhr = null;
}
return xhr;
}
var request = createCORSRequest("get","http://www.google.hk");
if(request) {
request.onload = function() {
//对request.reponseText进行处理
};
request.send();
}
其它跨域技术:
① 图像ping
与服务器进行简单、单向的跨域通信。请求的数据是通过查询字符串形式发送的,而响应可以是任意内容,但通常是像素图或204响应。通过图像ping,浏览器得不到任何具体的数据,但通过侦听load和error事件,能够知道响应是什么时候接收到的。
var img = new Image();
img.load = img.onerror = function() {
alert("Done");
};
img.src = "http://www.example.com/test?name=Carol";
图像ping方法常用于跟踪用户点击页面或动态广告曝光次数。图像ping有两个主要的缺点,一是只能发送GET请求,二是无法访问服务器的响应文本。因此图像ping只能用于浏览器与服务器间的单向通信。
②JSONP
JSON with padding,与json相比就是被包含在函数调用中的JSON
callback({"name":"carol"});
JSONP由两部分组成:毁掉函数和数据。回调函数是当响应到来时应该在也页面中调用的函数。调用函数名字一般是在请求中指定。而数据就是传入回调函数中的JSON数据。JSONP是通过动态<script>元素来使用的,使用的时候可以为src属性指定一个跨域URL。
function handleResponse(response) {
alert("you are at IP address" + response.ip + response.city);
}
var script = document.createElement("script");
script.src = "http://freegeoip.net/json/?callback=handleResponse";
document.body.insertbBefore(script,document.body.firseChild);
相比于图像ping,它的优点在于能够直接访问响应文本,支持浏览器与服务器之间双向通信。但是,跨域的不安全仍然存在。