本文全文参考了浏览器同源政策及其规避方法 - 阮一峰的网络日志,请支持愿意知识技术开源的作者,并保持自己的独立思考。
1. 为什么会有跨域问题?
面试中:
面试官:为什么会有跨域问题?
我:因为浏览器处于安全考虑,实行同源策略。
面试官:同源策略为什么安全?为什么脚本就可以跨域加载呢?
我:……@#¥%&!
既然出于安全考虑,为什么脚本可以直接跨域加载,但Ajax会被拒绝?为什么有那么多的跨域手段?真的是因为浏览器对此无能为力吗?
根源:同源策略:
同源策略1995年由 Netscape 公司引入浏览器。最初它的含义是指,网页不能访问非同源网页设置的Cookie。
很明显,因为Cookie中会保存用户的登录信息或提供给特定网站的敏感信息,当然会有严格的限制条件。而且,浏览器并不限制表单提交遵循同源策略。如果不加任何限制,恶意网站完全可以在前端拿到你的银行账户验证信息然后静默提交到自己的数据库中。
同源的定义:
- 协议相同
- 域名相同
- 端口相同
同源的限制范围:
随着互联网的发展,同源限制的范围越来越广。现在受限的行为有:
*(1) Cookie、LocalStorage 和 IndexDB 无法读取。
*(2) DOM 无法获得。
*(3) AJAX 请求不能发送。
2.规避跨域的方法总结
1. Cookie
Cookie限制比较严格。设置cookie的网页可以通过设置更松散的document.domain来放开权限。但是完全不在一个域名下的网页无法跨域。
前端设置:
/*
A: 'http://w1.example.com/a.html'
B: 'http://w2.example.com/b.html'
*/
document.domain = 'example.com';
不过一般cookie都是由服务器发送的,服务器语法:
Set-Cookie: key=value; domain=.example.com; path=/
2. LocalStorage 和 IndexDB
必须使用Html5新增语法PostMessage API。
3. iframe(DOM,跨域窗口通信)
- 如果两个窗口一级域名相同,只是二级域名不同,还是可以使用上面的
document.domain
属性 - 完全不同源的窗口:
- 片段识别符(fragment identifier)
父窗口发送信息:var src = originURL + '#' + data; document.getElementById('myIFrame').src = src;
子窗口获取信息:window.onhashchange = checkMessage;
子窗口发送信息:parent.location.href= target + "#" + hash;
- window.name
浏览器窗口有window.name属性。这个属性的最大特点是,无论是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页可以读取它。
(问题是子窗口将data写入window.name之后,需要跳转回主窗口同源的地址,才能被主窗口读取。网页性能下降。)- 跨文档通信API(Cross-document messaging)window.postMessage
3. window.postMessage
window.postMessage是Html5新增API,(不是破解,喜大普奔!)这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。
例:父窗口http://aaa.com向子窗口http://bbb.com发消息
var data = 'Hello World!';
var target_origin = 'http://bbb.com';
var origin = target_origin || '*';
var popup = window.open(target_origin, 'title');
popup.postMessage(data, origin);
反过来:
window.opener.postMessage('Nice to see you', 'http://aaa.com');
父子窗口获取信息都通过message事件:
window.addEventListener('message', function(event) {
console.log(event)
/*
event提供三个属性:
event.source:发送消息的窗口
event.origin: 消息发向的网址
event.data: 消息内容
*/
},false);
使用window.postMessage传什么都可以,传cookie也可以,因为读取操作是在原网页进行的。请注意安全性问题。
4. AJAX
先上解决方法:(很遗憾,均需要服务器端一定程度的支持)
- JSONP
- WebSocket
- CORS
JSONP不说了,尤其是使用jQuery的简直不要太简单。
-
WebSocket
WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。
重点是浏览器发出的WebSocket请求的头信息中的Origin字段。
正是因为有了Origin这个字段,所以WebSocket才没有实行同源政策。因为服务器可以根据这个字段,判断是否许可本次通信。如果该域名在白名单内,服务器就会做出如下回应。 -
CORS跨源资源分享(Cross-Origin Resource Sharing)
定义:MDN:HTTP访问控制(CORS)
阮一峰:跨域资源共享 CORS 详解 - 阮一峰的网络日志
具体操作:AJAX POST&跨域 解决方案 - CORS: CORS定义一种跨域访问的机制,可以让AJAX实现跨域访问。CORS 允许一个域上的网络应用向另一个域提交跨域 AJAX 请求。实现此功能非常简单,只需由服务器发送一个响应标头即可。
浏览器支持:Can I use...(CORS)
网友评论