资讯专栏INFORMATION COLUMN

跨域那些事儿

nevermind / 3038人阅读

摘要:什么是跨域我们先看下以下场景开启两个本地服务器,页面为,其中嵌套了,页面想使用页面的数据,例如调用它的方法,会报以下错误如图所示,,,译为协议主机和端口号必须符合,否则,就是跨域。跨域的几种常见方案同源策略的限制范围有以下几种和无法读取。

什么是跨域

我们先看下以下场景:
开启两个本地服务器,页面A为localhost:9800,其中嵌套了iframeB localhost:9000,页面A想使用页面B的数据,例如调用它的方法,会报以下错误

如图所示,Protocols,domains,and ports must match. 译为:协议、主机和端口号必须符合,否则,就是跨域。

下面我们来具体谈谈。

浏览器的同源策略

我们都知道,浏览器有个同源策略,也就是这个策略,限制了两个源中的资源相互交互。

Two pages have the same origin if the protocol, port (if one is specified), and host are the same for both pages.  

译为:如果两个页面有相同的协议、端口号和主机,那么这两个页面就属于同一个源。

也就是说,只有同一个源才可以进行资源共享。

我们来举几个例子,如果想和 http://www.test.com/index.html 进行通信:

URL Result Reason
http://www.test.com/page/othe... 允许
http://www.test.com/index.js 允许
http://a.test.com/index.html 不允许 子域不同
http://www.other.com/index.html 不允许 主域不同
https://www.test.com/index.html 不允许 协议不同
http://www.test.com:3000/index.html 不允许 端口不同

我们可以看到,协议、端口、主机缺一不可,必须完全匹配,上文就是由于端口号不同而报错。

那为什么要有同源策略的限制呢?原因也很简单,就是为了保证用户信息的安全,防止恶意的网站窃取数据。

试想一下,如果我们可以随意访问一个网站的cookie,那么岂不是随意窃取别别人登陆的cookie?如果没有同源策略,那互联网就太危险了。

跨域的几种常见方案

同源策略的限制范围有以下几种:

Cookie、LocalStorage 和 IndexDB 无法读取。

DOM 无法获得。

AJAX 请求不能发送。

而跨域访问,也无非两种情况:一是请求不同源下的接口(如上第3种);二是请求不同源的页面的资源(如上1、2,通常是页面中嵌套不同源的iframe要进行通信)。本文主要讨论第二种情况下造成的跨域,方法很多,主要介绍以下几种:document.domainlocation.hashwindow.namepostMessage

document.domain

适用于:主域相同子域不同的页面,例如上例中的第三种
方法:只需将这两个页面的document.domain设置为相同的父域名,即可实现不同子域名之间的跨域通信。

  
  
  

location.hash

一般来说,URL的任何改变都重新会加载一个新的网页,除了hash的变化,hash的任何改变都不会导致页面刷新。

在跨域解决方案中,hash也非常有用,来自不同源的页面可以相互设置对方的 URL,包括hash值,但不能获取对方的hash值。文档之间可以通过hash来相互通信。

流程(如上图):

主页面A中嵌入iframeB,两个来自不同域

主页面A中,将想要传递给B的字段,作为hash,将它与B的url连接起来,然后将B的src设置为连接后的url

iframeB中,就可以通过获取自己url的hash值,从而得到主页面传递的值,但在iframeB中,需设置一个定时器监听hash值的变化

除了设置定时器,还可以通过监听window.onhashchange事件

例子:启动两个本地服务器,主页面localhost:9800,子页面localhost:9000,主页面向子页面发消息











结果如下:点击button后,子页面将收到主页面的消息

注意:使用hash时最好对其进行编码、解码,否则在Firefox中会报错。因为Firefox会自动将hash值进行编码,如果不进行解码就无法JSON.parse().

两个页面不同源的情况下,IE、Chrome不允许修改parent.location.hash的值(Firefox可以),所以如果主页面想从子页面获取消息,只能借助一个代理iframe设置。

流程如下(两种):

子页面创建隐藏的代理iframe,与主页面同源,并将消息作为hash,设置到iframe的src中

代理页面将主页面的hash值设置为自身的hash

主页面使用定时器监听hash的变化

例子如下












结果如图:

这种方法的劣处就是将消息暴露在url中,因此也可以采用下文将讲述利用代理iframe跨域的方法,这边就不赘述了。

由于现在许多网站的hash已经被用于其他用途,此时想用hash跨域就会比较复杂了。这种情况下,我们可以使用一个同域的代理页面来完成

页面A想向页面B发送数据,流程如下:

页面A创建一个隐藏的代理iframeC,这个iframe与页面B同域

页面A中,将要发送的数据,作为hash,与页面Curl连接起来

代理iframeC中,它与B同域,可以直接调用页面B中的方法,这样便可以将hash值传递给B了

例子如下










结果如下:

缺点:

数据直接暴露在url中,安全性较低

url大小是有限制的,它支持传递的数据量较小

window.name

加载任何页面 window.name 的值始终保持不变

当页面A想从页面B中获取数据时:

页面A,创建一个隐藏的iframeC,将C的src指向页面B

页面C加载完成后,把响应的数据附加到window.name

C 取到数据后,将src设为任何一个与A同源的页面,这时 A 就能获取到 B 的name属性值

A 取到数据后,随时可以删掉 C

例子,启动两个本地服务器,页面Alocalhost:9800,页面Blocalhost:9000,页面A想从页面B中获取数据







结果如图

另外,两个页面还可相互通信
页面A通过hash,将数据传递给页面B,页面B仍通过window.name向页面A传递数据

场景如下:页面B存储了一些人的信息,页面B通过页面A的输入,获取不同人的信息








输入想获得的数据的id值,即可得到相应的信息

总结:
优点:容量很大,可以放置很长的字符串(2M左右,比url大得多)
缺点:必须要监听window.name属性的变化

window.postMessage()

HTML5规范中的新方法window.postMessage()可以用于安全跨域通信。当该方法调用时,将分发一个消息事件。对应的窗口通过事件监听来获取消息。

语法 :otherWindow.postMessage(message, targetOrigin)

otherWindow代表其他窗口的引用,例如iframe的contentWindow属性,通过window.open返回的窗体,通过window.frames[]返回的ifame对象。

message表示发送给其他窗口的数据

targetOrigin指定哪些来源的窗口可以接收到消息事件,其值可以是字符串"*"(表示无限制)或"/"(表示与父窗口同源)或一个URI。发送消息时,只有目标窗口的协议主机端口这三项都匹配targetOrigin提供的值,消息才会发送。

接收消息的窗口可以通过监听message事件,去接收消息

window.addEventListener("message", receiveMessage, false);

receiveMessage为接收到消息后的操作

message事件的事件对象event,提供三个属性:

event.source:发送消息的窗体(可以用来引用父窗口)

event.origin:消息发向的网址(可以过滤不是发给本窗口的消息)

event.data:消息内容

例子:启动两个本地服务器,页面Alocalhost:9800,页面Blocalhost:9000,页面A根据页面B发来的数据改变颜色





结果如下:点击按钮后,页面的div由灰变蓝

结语

关于跨域的就先聊到这啦~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/88072.html

相关文章

  • 说说跨域那些事儿

    摘要:首先纠正一个误区,跨域并非浏览器限制了发起跨站请求的这种能力,恰恰相反,我们可以发出请求,服务端也可以接收到请求并正常返回数据,只不过在返回之后浏览器会阻止非同源数据,从而在控制台打出一系列报错信息。 首先纠正一个误区,跨域并非浏览器限制了发起跨站请求的这种能力,恰恰相反,我们可以发出请求,服务端也可以接收到请求并正常返回数据,只不过在返回之后浏览器会阻止非同源数据(response...

    MadPecker 评论0 收藏0
  • 登录那些事儿

    摘要:假如是在同一个域名下,例如与,因为允许设置到二级域名下,所以和是可以共享的,用户的信息可以通过可逆加密放在二级域名下的,并且设置,就可以一站登录,站站登录。 原文链接:BlueSun | 登录那些事儿 也不知道是什么原因,刚开始不久的职业生涯,在技术这条路走着走着,和「登录」总是有着一个不解之缘。还记得当初学习Web编程的时候么?不管是Java、.Net、PHP,继经典「Hello W...

    layman 评论0 收藏0
  • node实现文件下载不得不说的那些事儿

    摘要:如果像本例中这样的场景会遇到这样一个问题,详见链接当请求参数过长或为了安全,就需要用到下载。写到这里自己都忍不住想锤自己,给自己挖坑不说,这样来回请求下载,流量,真的是败家。 这几天一直在做远程文件下载的事,现在总算有了解决,特来记录一下踩过的坑和想揍自己的心 需求 应用场景是这样的,底层逻辑数据请求接口是由Java写的,也就是说原始文件存在Java服务端,返回时有加密措施 由于工作...

    Coly 评论0 收藏0
  • [聊一聊系列]聊一聊前端功能统计那些事儿

    摘要:欢迎大家收看聊一聊系列,这一套系列文章,可以帮助前端工程师们了解前端的方方面面不仅仅是代码什么是功能统计作为一名开发,我们的产品发布出去之后,无论是产品还是运营,其实都是想及时了解产品对用户产生的影响的。下一章,我们将继续聊聊速度统计。 欢迎大家收看聊一聊系列,这一套系列文章,可以帮助前端工程师们了解前端的方方面面(不仅仅是代码):https://segmentfault.com/bl...

    PAMPANG 评论0 收藏0

发表评论

0条评论

nevermind

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<