程序员别唬我系列之:跨域与同源
关于跨域与同源,你造吗?
产品妹子脸憋的通红,一个劲儿的摇着头,委屈的小声说:“唉呀,前端开发说目前情况是产生了「跨域」问题,浏览器有「同源策略」保证安全性,突破不了,改动成本非常高,可是不改也不行啊,用户在线上反馈几天了,老大可生气了,我可怎么办啊,老大会不会以后不喜欢我了,呜呜呜”。
此时,正是我装逼的好时光,于是我一个箭(贱)步,跳到她面前,“哭毛啊,哥在这儿呢,好好说话~”。
「同源策略」「跨域」在前端开发(通常前端都是跟浏览器打交道哦,因为更靠近用户,更多的将后台数据展示给用户,所以叫前端)中,是很基本的常识,很多没做过前端开发的程序员其实也不是很了解这种策略和场景(注意,没有鄙视的意思,请不要乱扣帽子),更不用说很多产品同学,为了不再被忽悠,请听我九浅一深的解读。
先说iframe
首先说说iframe,iframe是html中的一个标签,它可以指定一个随意的Url地址,比如我写了个网页是www.a.com/index.html,内容如下:
iframe里面的src字段为www.qq.com,那这个网页打开之后,会看到腾讯网整个页面嵌入到了我写的这个index.html网页当中,iframe的意义非常简单,就是将一个Url地址嵌入到当前页面并展示出来。
你给远方的情郎写了一封情书,当把邮票贴在信封右上角的时候,信封为页面,邮票可以想象为一个iframe标签,它里面也描写很多内容(有山,有水,有人家)。
其中信封是在超市买的,邮票是在邮局买的,它俩生产厂家,品牌,材质,毫不相干,但组合在一起可以发挥作用。信封属于“超市”这个域,邮票属于“邮局”这个域。
有这样一种需求,一个网站有3个展示页面,每个页面都有一个评论区,那这个评论区可以封装为一个url,并用iframe嵌入到每个不同的页面当中去,全局复用一套评论区的代码,节省程序员,逻辑又好维护,只要一个人实现就可以了哦。
这就是iframe大概的用途,嵌入另一个页面,两个页面功能可以解耦和,不依赖对方而存在。
再说跨域
还是上面贴出来那一段简单代码,我已经写好了一个网页,跟腾讯网一模一样哦。
我动了坏心思,假设我有渠道能搞来流量,为啥我不在当前页面当中替换掉腾讯网的广告位置,而变成我的广告呢,靠这些流量不就把钱挣了嘛,而且用户也没什么感知,商业体验两不误,有没有任何的服务器和流量的花销。
于是我又开始改造代码了,争取能完成这个功能,分分钟走向人生巅峰呢~
这里在<script>标签中,我写了三句JS代码来描述整个流程(为了省去调试的时间,我用中文伪码代替),如果我真写了代码,这个功能也会被浏览器拒绝的,会提示「Permission Denied」之类的操作,也就是你无法篡改腾讯网的页面。
紧扣下小标题,当前「跨域」操作了。这种情况下浏览器直接拒绝掉了这种要求,否则baidu都能操作google页面了,那互联网世界就乱套了。
再再说同源策略
跨域被拒绝,其实是浏览器最底层的安全机制称为「同源策略」,啥是同源呢,建议先复习下以前关于URL的文章把URL五马分尸,只要协议,host,端口三个一样,就是同源的,否则就是非同源的。同源类比为宗教会比较容易理解,伊斯兰教信奉穆罕穆德,基督教信奉耶稣,这里是一个特征,同源要同时满足三个特征,举例如下:
不同源,因为host不同,一个为a.com,另一个为b.com。
不同源,因为协议不同,一个为http,另一个为https。
不同源,因为端口号不同,一个为80,另一个为81。
同源就是同域,所以才有跨域的说法,也可以说成跨源,一个意思。不同源,证明大家信奉的不是一个宗教。那自然不能修改另一个页面和拿到另一个页面相关的内容。只有同源的页面才可以相互访问的,因为同源代表了自己本身嘛。
浏览器提供了原生的同源机制来保证不同域下的网站互相是隔离的,安全的,正是这种机制的存在,才保证了web生态下各个网站不乱套。
总结:
从前有一个大户人家,大老爷牛逼,一辈子挣了不少钱,娶了五房姨太太,老大到老五各有各的心思,都惦记着大老爷那点钱儿,请问这种情况下,虽然大家住在一个大院里面,名义上是一家人,但是各家财务都是自负盈亏、独立结算,谁也不能把手伸到别人家去。
大老爷心知肚明光靠说是不管用的,必须要立家法,如果哪房姨太太手伸到别人家去了或者红杏出墙了,那就没收一切财产,并扫地出门,这是大老爷最后的底线。
大老爷就是浏览器,制定了一套规则(同源策略),五个姨太太(网页或网站)谁也不能偷到别人的财产,也不能去别人家捣乱,五个姨太太生活的平平稳稳,谁也不打扰谁。
但日子长了,五位太太还是闲不住的,东家长西家短的开始有了攀比之心和坏心思,她们注定是要交流的
- 我平时都用大宝,你的化妆品是啥牌子的?
- 你的LV是A货吧,我只背GUCCL的
- 快来看看我这50克拉的钻石
但是老爷又有规矩,不让她们交流,这咋办呢?
这也引出了最后一个问题,浏览器天生是拒绝非同源的网页沟通的,但是沟通需求无处不在。
比如上面举了个评论区的例子,如果评论区是iframe,当有一个新评论的时候,主页面要展示评论数+1,这个时候就产生了沟通的需求。一面是拒绝的,一面又要突破限制,似乎是矛盾的,你要玩儿欲擒故纵嘛,亲~~~
其实不冲突的,同源策略最基本的保证了域之间的隔离,如果要产生沟通,是要用一些附加的方法来实现的,比如后台的配合,两个网站之间的配合。就像有些国家本来是法律上拒绝同性恋的,但是如果双方愿意,也不反对。
合理的用于跨域沟通的方法有以下几种:
- JSONP
- iframe document.domain
- iframe location.hash
- HTML5 PostMessage
重点说下第4种,这是新的Html5规范,规定了跨域问题的解决办法,并且是异步的,大部分浏览器已经支持了,前面几种有一点hack的感觉,而且有的方法有些局限性,重点推荐第4种。如果你不知道这几种都是什么方案,用度娘查下,好多博客已经讲的比较清楚了,不墨迹了,有兴趣可以深入了解下。
如果从事产品工作,能知道跨域和同源的基本概念,并且知道为什么产生了这个问题,当前是什么状态,大概的解决方案是什么,你就已经很优秀了,你是最棒的~
#专栏作家#
给产品经理讲技术,微信公众号(pm_teacher),人人都是产品经理专栏作家。资深程序猿,专注客户端开发若干年,对前端、后台技术略懂,热衷于对新的科技领域的探索。
本文原创发布于人人都是产品经理。未经许可,禁止转载。
题图来自PEXELS,基于CC0协议
爱你~
比喻是亮点~ 😉
写得不错的
没看懂