本文源自一次内部关于跨域的讨论分享的总结javascript
理解跨域的重点在于:了解跨域产生的场景、原理html
跨域问题只在浏览器客户端环境下出现,是因为浏览器出于安全考虑设置的同源策略引发,因此解决跨域问题通常采用的思路有两种:
a. 绕过浏览器的同源策略约束
b. 遵循新的跨域规范java
同源策略:不一样域的客户端在没明确受权的状况下,不能读写对方的资源
同域:协议、域名、端口号均相同
好比:ajax
http://abc.com vs https://abc.com http://ab.abc.com vs http://a.abc.com 127.0.0.1:3000 vs 127.0.0.1:4000
哪些行为会受到浏览器同源策略的约束呢?json
等等canvas
哪些标签能够加载非同源资源?
script img link iframe
跨域方案的思路a也就是基于以上几种标签后端
json with padding跨域
基本原理:利用script标签的src属性容许加载非同源资源,加载后js解析器将执行资源代码,目标服务器在数据外层包裹一个客户端已经定义好的函数并返回浏览器
服务端接口返回一段可执行js脚本
"hello browser" => callback("hello browser")安全
优:
缺:
在淘宝(www.taobao.com)登陆后,切换到天猫(www.tmall.com),会看到顶栏已经有登陆用户信息。打开控制台,刷新tmall页面,能够看到以下jsonp请求,其中第一个即为获取到登陆信息的关键请求:
打开该请求的Response内容:
这段返回内容(本质上是js代码)到达客户端后,将会被解析执行
@Update :不论是post message、window.name共享、location.hash共享,这类方案的原理都是依赖消息通讯机制实现的,故更改标题
以我的常常用到的Frame代理为例
基本原理:在目标服务器放置一个代理文件(proxy_frame.html),经过加载该代理文件和服务端进行数据交互(同域请求),返回数据经过消息通信(如post message)返回给上层应用以实现跨域数据交互
a.b.com域页面
其实是利用窗体之间通信方式 将跨域请求转化为同域请求
针对高版本浏览器:HTML5 Web Message
针对Trident引擎低版本浏览器(ie6-7):window.name代理(复杂结构须要stringify,启用队列修改)
优:
缺:
为了解决跨域问题出现的标准规范
经过增长一系列请求头和响应头,规范安全地进行跨站数据传输,它要求浏览器必须能支持CORS规范定义的请求头和策略执行,而且服务端须要解析这些新的请求头并按照策略返回对应的响应头和请求的资源
分为如下三种请求场景:
响应头:
请求头:
直接使用ajax(根据浏览器版本选择XHR或XDR对象)或fetch便可,客户端只需按规范设置请求头
服务端按规范识别并返回对应响应头,还能够对请求域名进行过滤处理
好比使用Nginx配置:(待补充)
客户端发起一个get请求,观察一次成功简单请求的请求头与响应头:
客户端发起一个post请求,并设置Content-Type为application/xml,观察一次成功预检+正式请求的请求头与响应头:
客户端发起一个post请求,并设置设置特殊标志位 withCredentials为true ,观察一次成功预检+正式请求的请求头与响应头:
优:
缺:
IE6-7 彻底不支持CORS
IE8-9 仅支持不带凭证的CORS跨域请求
创建socket长链接,须要验证,本质上能够视为安全,不存在跨域限制
因为资源消耗较大,除了一些特殊场景,通常不使用
将本域服务端配置成 须要跨域获取的资源的 反向代理服务器
好比:使用Nginx配置请求转发:proxy_pass
与frame代理模式相似,请求经过Flash来发送(proxy_flash.swf放置在同源站),利用Flash的策略文件crossdomain.xml来控制资源的共享权限,获取目标服务器请求返回数据
---至关于把iframe改为flash
还有例如 img ping 等等等等
跨域永远是无奈之举,常规状况下不该该出现
针对少许须要跨域Get请求的场景 : JSONP还是不错的选择
针对整站大量跨域请求 :
—— 兼容性要求高: iFrame代理跨域/服务端反向代理
—— IE10以上兼容支持: CORS规范
检测浏览器支持: 高版本使用CORS规范,低版本自动降级使用iFrame代理