同源是指相同的协议、域名、端口,三者都相同才属于同域。不符合上述定义的请求,则称为跨域。
相信每个开发人员都曾遇到过跨域请求的情况,虽然情况不一样,但问题的本质都可以归为浏览器出于安全考虑下的同源策略的限制。
跨域的情形有很多,最常见的有Ajax跨域、Socket跨域和Canvas跨域。下面列举一些我们常见的跨域情形下,某些浏览器控制台给出的错误提示:
FireFox下的提示:
已阻止交叉源请求:同源策略不允许读取***上的远程资源。可以将资源移动到相同的域名上或者启用 CORS 来解决这个问题。
Canvas跨域Chrome下的提示:
UncaughtSecurityError:Failed to execute'getImageData' on 'CanvasRenderingContext2D':The canvas has been taintedby cross-origin data.
或:
Imagefrom origin 'http://js.xx.com' has been blocked from loading by Cross-OriginResource Sharing policy: No 'Access-Control-Allow-Origin' header is present onthe requested resource. Origin 'http://act.xx.com' is therefore not allowedaccess.
网上有许多解决跨域的方法,大体上有这几种:
1)document.domain+iframe的设置
2)动态创建script
3)利用iframe和location.hash
4)window.name实现的跨域数据传输
5)使用HTML5 postMessage
6)利用flash
7)通过代理,js访问代理,代理转到不同的域
8)Jquery JSONP(不能成为真正的Ajax,本质上仍是动态创建script)
9)跨域资源共享(CORS) 这是HTML5跨域问题的标准解决方案
说明:方案1~方案6见Rain Man所写的文章《JavaScript跨域总结与解决办法》
下面主要就我总结的几种解决跨域的方法,展开说一下。
1) 绕开跨域。
适用情形是:动静分离。
example1.com域名下的页面中跨域请求是以JavaScript内联方式实现的,而请求的目标静态资源是放在example2.com域名下,这时可以将执行跨域请求的JavaScript代码块独立出来,放到example2.com上,而example1.com页面通过外联方式引入该静态域名下的js文件。这样,js与请求的图片等资源都在example2.com下,即可正常访问到。这种方法其实是一种巧妙避开跨域的方法。
2) 后台抓取克隆图片。
适用情形:动静不分离(两个域名均运行访问静态资源)。
example1.com请求example2.com下的资源图片,可以使用PHP抓取图片并在example2.com下生成一份,这样就可以间接访问到example1.com的静态资源。
html模板示例代码:
$("#scratchpad").wScratchPad({ //刮刮卡示例,当前域名
width:283,
height:154,
//color: "#a9a9a7",
image2:"imgdata.php?url=http://js.xxx.com/static/activity/sq/guagua315/images/card_inner.jpg",
scratchMove:function() {
}
});
或:
xi=newXMLHttpRequest();
xi.open("GET","imgdata.php?url="+yourImageURL,true);
xi.send();
xi.onreadystatechange=function() {
if(xi.readyState==4 && xi.status==200) {
img=newImage;
img.onload=function(){
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
}
img.src=xi.responseText;
}
}
PHP处理代码:
<?php//imgdata.php
$url=$_GET['url'];
$img =file_get_contents($url);
$imgname = substr(strrchr($url,"/"),1);
file_put_contents($fn,$img);
echo $imgname;
?>
上述代码在当前php目录下生成了克隆生成了一张图片。
3) 后台程序设置Access-Control-Allow-Origin
适用情形:Ajax获取跨域接口的JSON数据。
example1.com请求example2.com的数据接口,则需要在example2.com的数据接口添加跨域访问授权。
PHP程序中开始出添加header('HeaderName:HeaderValue'); 这样的header标记:
header('Access-Control-Allow-Origin:*');
4)修改服务器配置启用CORS
适用情形:跨域访问静态资源。
Access-Control-Allow-Origin是什么作用呢?用于授权资源的跨站访问。比如,静态资源图片都放在example2.com 域名下, 如果在返回的头中没有设置 Access-Control-Allow-Origin , 那么别的域是没有权限外链你的图片的。
要实现CORS跨域,服务端需要这个一个流程,图片引自html5rocks,附图如下
a. 对于简单请求,如GET,只需要在HTTP Response后添加Access-Control-Allow-Origin。