跨域与常用方案

2018-03-19  本文已影响0人  744354889606

本文源自一次内部关于跨域的讨论分享的总结

理解跨域的重点在于:了解跨域产生的场景、原理

跨域问题只在浏览器客户端环境下出现,是由于浏览器出于安全考虑设置的同源策略引起,所以解决跨域问题一般采用的思路有两种:
a. 绕过浏览器的同源策略约束
b. 遵循新的跨域规范

浏览器同源策略

同源策略:不同域的客户端在没明确授权的情况下,不能读写对方的资源
同域:协议、域名、端口号均相同
比如:

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

哪些行为会受到浏览器同源策略的约束呢?

哪些标签可以加载非同源资源?
script img link iframe
跨域方案的思路a也就是基于以上几种标签

JSONP -- 思路满分

json with padding

基本原理:利用script标签的src属性允许加载非同源资源,加载后js解析器将执行资源代码,目标服务器在数据外层包裹一个客户端已经定义好的函数并返回

服务端接口返回一段可执行js脚本
"hello browser" => callback("hello browser")

前后端交互流程:

jsonp前后端交互流程

优缺点对比

优:

栗子 ——淘宝和天猫通过jsonp跨域共享cookie

在淘宝(www.taobao.com)登录后,切换到天猫(www.tmall.com),会看到顶栏已经有登录用户信息。打开控制台,刷新tmall页面,可以看到如下jsonp请求,其中第一个即为获取到登录信息的关键请求:

获取共享登录cookie信息的jsonp请求

打开该请求的Response内容:


response内容

这段返回内容(本质上是js代码)到达客户端后,将会被解析执行

利用消息通信机制实现的跨域请求

@Update :不管是post message、window.name共享、location.hash共享,这类方案的原理都是依赖消息通信机制实现的,故更改标题

以个人经常用到的Frame代理为例

基本原理:在目标服务器放置一个代理文件(proxy_frame.html),通过加载该代理文件和服务端进行数据交互(同域请求),返回数据通过消息通讯(如post message)返回给上层应用以实现跨域数据交互
a.b.com域页面

加载跨域iframe文件
实际上是利用窗体之间通讯方式 将跨域请求转化为同域请求

前后端交互流程:(以nej框架的实现为例)

iframe跨域前后端交互流程

窗体间消息通信方式:

针对高版本浏览器:HTML5 Web Message
针对Trident引擎低版本浏览器(ie6-7):window.name代理(复杂结构需要stringify,启用队列修改)


image.png
image.png

优缺点对比:

优:

缺:

Cross-Origin Resource Sharing规范 -- 简称CORS

为了解决跨域问题出现的标准规范
通过增加一系列请求头和响应头规范安全地进行跨站数据传输,它要求浏览器必须能支持CORS规范定义的请求头和策略执行,并且服务端需要解析这些新的请求头并按照策略返回对应的响应头和请求的资源

分为以下三种请求场景:


cors规范三种请求场景

附录:对 CORS 安全的首部字段集合

相关请求头和响应头(主要)

响应头:


响应头说明

请求头:


请求头说明

如何使用?

直接使用ajax(根据浏览器版本选择XHR或XDR对象)或fetch即可,客户端只需按规范设置请求头
服务端按规范识别并返回对应响应头,还可以对请求域名进行过滤处理
比如使用Nginx配置:(待补充)

还是看几个栗子:

客户端发起一个get请求,观察一次成功简单请求的请求头与响应头:

image.png

客户端发起一个post请求,并设置Content-Type为application/xml,观察一次成功预检+正式请求的请求头与响应头:

Options预检
Post正式

客户端发起一个post请求,并设置设置特殊标志位 withCredentials为true ,观察一次成功预检+正式请求的请求头与响应头:

Options预检
Post正式

优缺点:

优:

缺:

其他

WebSocket

建立socket长连接,需要验证,本质上可以视为安全,不存在跨域限制
由于资源消耗较大,除了一些特殊场景,一般不使用

服务端反向代理

将本域服务端配置成 需要跨域获取的资源的 反向代理服务器
比如:使用Nginx配置请求转发:proxy_pass


反向代理

FLASH代理

与frame代理模式类似,请求通过Flash来发送(proxy_flash.swf放置在同源站),利用Flash的策略文件crossdomain.xml来控制资源的共享权限,获取目标服务器请求返回数据
---相当于把iframe改成flash

还有例如 img ping 等等等等

总结

跨域永远是无奈之举,常规情况下不应该出现

针对少量需要跨域Get请求的场景 : JSONP仍是不错的选择
针对整站大量跨域请求 :
—— 兼容性要求高: iFrame代理跨域/服务端反向代理

—— IE10以上兼容支持: CORS规范

检测浏览器支持: 高版本使用CORS规范,低版本自动降级使用iFrame代理

上一篇 下一篇

猜你喜欢

热点阅读