之前在项目中用 HTML5 提供的 XHR2 草草地临时性解决了一个 ajax 的跨域问题。其实跨域这东东还是大有乾坤的,今天来深入扒一扒。
1 什么是跨域
同源策略可以一定程度上保证web的安全。跨域,简单地说:由于同源策略的限制,a.com
域名下无法跟 b.com
域名进行数据的请求交互。
比如,我在一个合法的网站A上注册了个人信息;注册完了之后,我又去一家不安全的网站B去转转。万一恶意网站B、跑去合法网站A、盗取了我的个人信息……后果是不是很严重的样子?所以同源策略还是为咱用户着想的。但是有时候,在安全的情况下,我们又希望可以突破同源策略限制去跨域请求。这又该怎么办呢?
具体属于跨域的情况如下:
域名url | 说明 | 跨域情况 |
---|---|---|
http://www.a.com/a.js http://www.a.com/b.js |
同一域名下不同文件 | 允许 |
http://www.a.com/lib/a.js http://www.a.com/main/b.js |
同一域名下不同文件路径的文件 | 允许 |
http://www.a.com:4000/a.js http://www.a.com/b.js |
同一域名、端口不同 | 不允许 |
http://www.a.com/a.js https://www.a.com/b.js |
同一域名、协议不同 | 不允许 |
http://www.a.com/a.js http://127.0.0.1/b.js |
域名、域名对应的ip | 不允许 |
http://www.a.com/a.js http://ccc.a.com/b.js |
主域名(一级)同、子域名(二级)不同 | 不允许 |
http://www.a.com/a.js http://www.b.com/b.js |
域名完全不同 | 不允许 |
何为同源?总结:协议相同、端口相同、域名相同
同源策略主要对三种跨域行为造成了限制:
- ajax 请求报错
- cookie、localStorage、indexDB 无法读取
- DOM 新窗口(iframe,window.open)获取不到
2 ajax 跨域的解决方法
2.1 jsonp 解决 ajax 跨域
jsonp 原理:
同源策略下,在某个服务器下的页面是无法获取到该服务器以外的数据的,但img、iframe、script等标签是个例外,这些标签可以通过src属性请求到其他服务器上的数据。
利用script标签的开放策略,我们可以实现跨域请求数据,当然,也需要服务端的配合。当我们正常地请求一个JSON数据的时候,服务端返回的是一串JSON类型的数据,而我们使用JSONP模式来请求数据的时候,服务端返回的是一段可执行的JavaScript代码。
jsonp 实现的过程:
后台页面 ‘http://www.bbb.com/user‘ 返回的 jsonp 数据如下:
|
|
请求页面 http://www.aaa.com/
中: 动态创建<script>
标签跨域调用、并定义函数 foo
:
|
|
jquery中使用jsonp:
|
|
JavaScript中使用jsonp:
|
|
2.2 代理(中间过渡)解决 ajax 跨域
代理解决 ajax 跨域问题的实现技术主要偏后台,这里只是简单地介绍一下实现的原理。
在域 domain1.com
下有2个文件:a.php
、daili.php
;
在域 domain2.com
下有1个文件:b.php
;domain1.com
的 a.php
向 domain2.com
的 b.php
请求,跨域不允许;
domain1.com
的 a.php
向 domain1.com
的 daili.php
请求,允许;
在服务器端,domain1.com
的 daili.php
向 domain2.com
的 b.php
请求,允许; daili.php
吧请求到的数据再返回给同域的 a.php
,完成。
2.3 CORS跨域资源共享
( 参考:javascipt高级程序设计 )
CORS,跨域资源共享。它定义了在必须访问跨域资源时、浏览器与服务器应该如何沟通。CORS的基本思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求应该成功还是失败。
比如,一个简单的 get 或 post 请求,它没有自定义的头部;需要给它附加一个额外的 origin
头部,包含请求页面的源信息(协议、端口、域名);服务器根据这个头部信息来决定是否给予响应。
IE和其它浏览器对 CORS 的实现方式各不相同(IE8支持)。这里写一个跨浏览器的方法:
|
|
HTML5 提供的XHR2
HTML5 提供的 XMLHttpRequest Level2 已经实现了跨域访问,只是 IE10支持。只需要在后台PHP中设置表头 header
即可。
比如:http://www.aaa.com
打算跨域向 http://www.bbb.com
请求数据,报错“源不匹配”;这时,我们在 http://www.bbb.com
设置 header
即可。
|
|
3 cookie 跨域的解决方法(略)
通过设置 document.domain 共享 cookie。
如:一级域名相同、二级域名不同的两个页面:http://www.aaa.com/a.html
http://yyy.aaa.com/b.html
以上2个页面均设置相同的 domain
: document.domain = 'aaa.com';
这样,两个页面就可以互相读取对方所设置的 cookie
了。
注意:cookie 的路径。
4 iframe 跨域的解决方法(略)
感觉 iframe 这东西暂时用得比较少,此处略为学习一下。
iframe 和 window.open 方法打开的不是同源的窗口,它们与父窗口无法通信。
解决方法大概主要有以下四种:
- window.name
- window.postMessage (html5)
- localStorage
- URL的#号hash值
学习参考:
- http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
- javascript高级程序设计