跨域问题
跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器施加的安全限制。
所谓同源是指,域名,协议,端口均相同,只要有一个不同,就是跨域。不明白没关系,举个栗子:
http://www.123.com/index.html 调用 http://www.123.com/server.php (非跨域)
http://www.123.com/index.html 调用 http://www.456.com/server.php (主域名不同:123/456,跨域)
http://abc.123.com/index.html 调用 http://def.123.com/server.php (子域名不同:abc/def,跨域)
http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)
http://www.123.com/index.html 调用 https://www.123.com/server.php (协议不同:http/https,跨域)
请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。
浏览器执行javascript脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行。
跨域会阻止什么操作?
浏览器是从两个方面去做这个同源策略的,一是针对接口的请求,二是针对Dom的查询
1.阻止接口请求
2.阻止dom获取和操作
比如a页面中嵌入了iframe,src为不同源的b页面,则在a中无法操作b中的dom,也没有办法改变b中dom中的css样式。而如果ab是同源的话是可以获取并操作的。
浏览器会阻止非同源操作dom,浏览器的这个限制虽然不能保证完全安全,但是会增加攻击的困难性,可以抵御坏人入侵,但有时我们自己需要跨域请求接口数据或者操作自己的dom,也被浏览器阻止了,所以就需要跨域,跨域的前提肯定是你和服务器是一伙的,你可以控制服务器返回的数据,否则跨域是无法完成的
解决跨域的方法
1.前端方法jsonp
jsonp(JSON with Padding:填充式JSON)是前端解决跨域最实用的方法
原理就是html中 的link,href,src属性都是不受跨域影响的,link可以调用远程的css文件,href可以链接到随便的url上,图片的src可以随意引用图片,script的src属性可以随意引入不同源的js文件
<script type="text/javascript">
function func1(ret){console.log(ret)}
</script>
<script src="http://192.168.100.150:8081/zhxZone/webmana/dict/jsonp.js" type="text/javascript" charset="utf-8"></script>
而引入的jsonp.js中的代码为:
func1('acttan')
可想而知结果会打印出acttan,也就是说a页面获取到了jsonp.js中的数据,数据是以调用方法并将数据放到参数中返回来的
但是这样获取数据,必须a.html中的方法名与js中的引用方法名相同,这样就是麻烦很多,最好是a.html能将方法名动态的传给后台,后台返回的引入方法名就用我传给后台的方法名,这样就做到了由前台控制方法名,
而且缺点也很明显 只支持get请求、不支持post请求
2.通过 CORS解决跨域
header(‘Access-Control-Allow-Origin:*’);//允许所有来源访问
header(‘Access-Control-Allow-Method:POST,GET’);//允许访问的方式
3.nginx反向代理:
上个方法跨域是借助了浏览器对 Access-Control-Allow-Origin 的支持。但有些浏览器是不支持的,所以这并非是最佳方案,现在我们来利用nginx 通过反向代理 满足浏览器的同源策略实现跨域!
www.baidu.com/index.html需要调用www.sina.com/server.php,可以写一个接口www.baidu.com/server.php,由这个接口在后端去调用www.sina.com/server.php并拿到返回值,然后再返回给index.html
4.通过修改document.domain来跨子域:
跨域分为两种,一种xhr不能访问不同源的文档,另一种是不同window之间不能进行交互操作;
document.domain只能解决第二种,即这两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域.
Javascript出于对安全性的考虑,而禁止两个或者多个不同域的页面进行互相操作。
相同域的页面在相互操作的时候不会有任何问题。
比如在:aaa.com的一个网页(a.html)里面 利用iframe引入了一个bbb.com里的一个网页(b.html)。
这时在a.html里面可以看到b.html里的内容,但是却不能利用javascript来操作它。因为这两个页面属于不同的域,在操作之前,js会检测两个页面的域是否相等,如果相等,就允许其操作,如果不相等,就会拒绝操作。
这里不可能把a.html与b.html利用JS改成同一个域的。因为它们的基础域名不相等。(强制用JS将它们改成相等的域的话会报跟上面一样的"参数无效错误。")
所以如果在a.html里引入aaa.com里的另一个网页,是不会有这个问题的,因为域相等。
有另一种情况,两个子域名:
aaa.example.com
bbb.example.com
aaa里的一个网页(a.html)引入了bbb 里的一个网页(b.html),
这时a.html里同样是不能操作b.html里面的内容的。
因为document.domain不一样,一个是aaa.example.com,另一个是bbb.example.com。
这时我们就可以通过Javascript,将两个页面的domain改成一样的,
需要在a.html加入:
<iframe id="iframe" src="http://aaa.example.com/b.html" onload = "test()"></iframe> <script type="text/javascript"> document.domain = 'example.com';//设置成主域 function test(){ alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 对象 } </script>
在页面 b.html加入
<script type="text/javascript"> document.domain = 'example.com';//设置成主域</script>
5.通过HTML5中新引进的window.postMessage方法来跨域传送数据:
跨域和被跨域的一方都是你可以控制的,一方写发送消息的,另一方写接收消息方法
1.发送消息
window.postMessage('这是要发送的消息','*');
有两个参数,第一个参数是要发送的信息,可以是字符串也可以是json字符串,可传递较多信息。第二个参数是可以指定域名,也就是说只有符合这个域名才他发消息,如果写“*”的话不管域名是啥,只要在同一个window就给它发消息。
2.接受消息
window.parent.addEventListener("message",function(res){
console.log(res)
})
注意这跨域的局限性在于必须在同一个window对象上,也就是说哪个window发送消息,只有本window才能接收到。
因为收发消息都是js代码,所以这本质是用js的方法跨域,双方都要写js.
6.通过window.name跨域
window对象有一个name属性,该属性有一个特征:即在一个窗口的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每一个页面对window.name都有读写的权限,window.name是持久的存在于一个窗口载入的所有页面中的,并不会因为新的页面的载入而被重置。
a.html中的代码
<script> window.name = '我是页面a中设置的值'; setInterval(function(){ window.location = 'b.html'; },2000)//两秒后把一个新页面b.html载入到当前的window中 </script>
b.html中的代码
<script>
console.log(window.name);//读取window.name的值
</script>
我们可以看到b.html页面上成功输出了a.html页面中设置的window.name的值,如果在之后所有载入的页面都没对window.name进行修改的话,那么所有的这些页面获取到的window.name的值都是a.html页面中设置的那个值;
不过要注意的是:window.name的值只能是字符串的形式,这个字符串的大小最大只能允许2M左右,具体取决于不同的浏览器,但是一般是够用了。
举个跨域的例子:(利用隐藏的iframe作为中间人来为a.html获取data.html的window.name的值
<body>
<iframe id="proxy" src="http://www.cnblogs.com/data.html" style="display: none;" onload = "getData()">
<script>
function getData(){
var iframe = document.getElementById('proxy);
iframe.onload = function(){
let data = iframe.contentWindow.name;
//上述即为获取iframe里的window.name也就是data.html页面中所设置的数据;
}
iframe.src = 'b.html';
}
</script>
</body>

浙公网安备 33010602011771号