一、什么是跨域
JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。但在安全限制的同时也给注入iframe或是ajax应用上带来了不少麻烦。
首先什么是跨域,简单地理解就是因为JavaScript同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象。
特别注意两点:
第一,如果是协议和端口造成的跨域问题“前台”是无能为力的,
第二:在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。
“URL的首部”指window.location.protocol +window.location.host
http://127.0.0.1/
https://127.0.0.1/
下的对象。更详细的说明可以看下表:
URL |
说明 |
是否允许通信 |
http://www.a.com/a.js |
同一域名下 |
允许 |
http://www.a.com/lab/a.js |
同一域名下不同文件夹 |
允许 |
http://www.a.com:8000/a.js |
同一域名,不同端口 |
不允许 |
http://www.a.com/a.js |
同一域名,不同协议 |
不允许 |
http://www.a.com/a.js |
域名和域名对应ip |
不允许 |
http://www.a.com/a.js |
主域相同,子域不同 |
不允许 |
http://www.a.com/a.js |
同一域名,不同二级域名(同上) |
不允许(cookie这种情况下也不允许访问) |
http://www.cnblogs.com/a.js |
不同域名 |
不允许 |
二、下面来介绍在实际的开发中常遇到的情况
2.1使用HTML5 postMessage
2.1.1 创建目录:
www/a.com/index.html www/b.com/index.html
2.1.2 配置你的apache
在 Apache2/httpd.con/ 文件里面找到
Include conf/extra/httpd-vhosts.conf 去掉前面的#
在Apache2/conf/extra/httpd-vhosts.conf中修改或者添加如下代码:
<VirtualHost *:80>
DocumentRoot "D:/www/a.com"
ServerName www.a.com
ServerAlias a.com
ErrorLog "D:/www/logs/a.com-error.log"
CustomLog "D:/www/logs/a.com-error.log-access.log" common
</VirtualHost>
<VirtualHost *:80>
DocumentRoot "D:/www/b.com"
ServerName www.b.com
ServerAlias b.com
ErrorLog "D:/www/logs/b.com-error.log"
CustomLog "D:/www/logs/b.com-error.log-access.log" common
</VirtualHost>
2.1.3 找到C:\WINDOWS\system32\drivers\etc\hosts 文件添加如下如下代码:
127.0.0.1 localhost
127.0.0.1 a.com
127.0.0.1 b.com
重启服务器
http://a.com/a.html
http://b.com/b.html
代码如下:
A.com/index.html --注意: 我们访问的是a.com 演示的目的:在于跨域传递数据
创建iframe 并指向b.com/index.html文件
<iframe id="ifr" src="http://b.com/index.html" style="display: none; border: 0;margin:0;padding: 0;"></iframe>
<script type="text/javascript">
window.onload = function() { //触发事件 当触发事件的时候
var ifr = document.getElementById('ifr');
var targetOrigin = 'http://b.com/'; // 若写成'http://b.com/c/proxy.html'效果一样 // 若写成'http://c.com'就不会执行postMessage 这个是html的特性
ifr.contentWindow.postMessage('I was there!', targetOrigin); //发送数据
//a.com 把数据发送个给b.com
};
</script>
B.com/index.html
<script type="text/javascript">
window.addEventListener('message', function(event){
// 通过origin属性判断消息来源地址
if (event.origin == 'http://a.com') {
alert('我接收到了数据'+event.data); // 弹出"I was there!"
//b.com 接收到了来自a.com的数据信息并弹出
}
}, false);
</script>
原理:
HTML5中最酷的新功能之一就是 跨文档消息传输Cross Document Messaging。下一代浏览器都将支持这个功能:Chrome 2.0+、Internet Explorer9.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。 Facebook已经使用了这个功能,用postMessage支持基于web的实时消息传递。
message: 所要发送的数据,string类型。
targetOrigin: 用于限制otherWindow,“*”表示不作限制
2.2jquery+php+json实现跨域数据请求与传输
JSON和JSONP虽然只有一个字母的差别,但其实他们根本不是一回事儿:JSON是一种数据交换格式,而JSONP是一种依靠开发人员的聪明才智创造出的一种非官方跨域数据交互协议。
我们拿最近比较火的谍战片来打个比方,JSON是地下党们用来书写和交换情报的“暗号”,而JSONP则是把用暗号书写的情报传递给自己同志时使用的接头方式。看到没?一个是描述信息的格式,一个是信息传递双方约定的方法。
Jsonp的产生:
1. 一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web服务、WCF,只要是跨域请求,一律不准;
2.不过我们又发现,Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有"src"这个属性的标签都拥有跨域的能力,比如<script>、<img>、<iframe>);
比如:
远程服务器http://www.b.com根目录下有个alter.js文件代码如下:
alert('我是远程文件');
本地服务器http://www.a.com下有个jsonp.html页面代码如下:
在body 中添加如下代码:
<script type="text/javascript" src="http://www.b.com/alter.js"></script>
结果: 毫无疑问,页面将会弹出一个提示窗体,显示跨域调用成功。
下面我们再来举一个案例:
在本地的 http://www.a.com/ 创建一个js 函数
注意这段代码的顺序:
<script type="text/javascript">
var localHandler = function(data){
alert('我是本地函数,可以跨域调用www.b.com/alert.js,远程js带来的数据是:' + data.result);
};
</script>
<script type="text/javascript" src="http://www.b.com/remote.js"></script>
在远程的服务器的 www.b.com/alert.js 里面写如下代码:
localHandler({"result":"我是远程js带来的数据"}); json格式数据
原理: 通过上面的案例我们了解到只要服务器端是一个动态的js函数,服务器就可以按照客户端的需求来生成js脚本并响应了。就可以实现跨域了
下面我们用jquery提供的jsonp来实现
在 a.com/index.html
<input type="text" name="mydata" id="mydata" /> 当鼠标移除文本框的时候
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('#mydata').bind('blur',function(){
var url='http://www.b.com/test.php?mydata='+$(this).val();
访问 www.b.com/test.php 并传递参数到b.com的服务器端
$.ajax({
type: 'get',
url:url ,
dataType: 'jsonp', //传输类型是 jsonp
jsonpCallback:'filterHander', //服务器端的动态js函数名 也可以不写
如果为空 那么在服务器的端的返回就 $_GET[‘Callback’].({...})
success:function(json){
// alert(json.title); //打印数据
//alert(json.mydata);
alert(json.a);
},
error:function(){
alert('error');
}
});
});
})
</script>
下面是 www.b.com/test.php
if(isset($_GET['mydata'])){
//echo 'filterHander({title: "我b.com下面的test.php返回的标题",mydata:"你的是参数是:'.$_GET['mydata'].'"})';
echo 'filterHander('.json_encode( $data=array('a'=>'aa','b'=>'bb')).')';
}