资讯专栏INFORMATION COLUMN

前端跨域

Coding01 / 2399人阅读

摘要:在所有以上提到的跨域方法中,不得不说都是利用了大大小小的漏洞来绕过同源策略。对于开发者来说最大的好处就是,无需考虑以什么样的方式绕过同源策略请求跨域资源,直接使用即可。

HTML跨域 传统跨域方式 JSONP跨域

说到传统跨域方式,JSONP是最广泛为人所知的形式了。

对于JS来说,利用XMLHttpRequest无法请求非本域上的数据,但是却可以加载非本域的JS文件。
JSONP就是利用了这个所谓的“漏洞”。

试想当我们在文档中插入一个script标签,请求一个 JS 文件时,该JS文件的内容是直接调用一个函数,
同时传入适当的数据。则对于方法内部,就已经可以通过参数的形式获取传入的数据。如下所示:

此处的对象,就是传入的数据,而fun则是那个函数。该函数其实可以是任意函数名,只需在我们的window域下定义,也可以根据需求定义在其他地方。问题在于传入的数据怎么来呢?其实这些对于前端来说完全不用管,只需让后端处理好后拼接成如上形式返回给我们即可。而fun里面放什么,则取决于你要对返回的数据做什么样的处理了。

另外,fun的函数名建议是随同跨域接口一起传输给server,以让server来进行拼接出合适的执行代码。完整代码如下:

document.domain

也许你会遇到这样的情形:我的网页内嵌了一个iframe,该iframe所引用的页面跟我本域不一样,此时我想修改iframe中的内容,该怎么办呢?

或许你认为可以通过contentWindow获取iframe中的内容,但很可惜的是我们拿到这个contentWindow,却不能获取到里面的属性与方法(H5最新属性postMessage除外,后面会提及)。

这是因为浏览器的同源策略禁止了我们这样的操作,因为它们分属不同的源。

此时就需要用到document.domain了,也就是我们只需将iframe中的document.domain设置成跟父页面相同的值即可。

比如当 http://loliner.baidu.com/inde... 内嵌了 http://baidu.com/example.html ,此时我们只需将 index.html 的 document.domain 修改成 baidu.com即可实现与example.html通信。

但是问题来了,浏览器对document.domain的设置是有限制的,其只能设置成比自身域更高一级的域名,包括自身域。

比如存在http://b.a.com/index.html,则该页面 document.domain允许的值为

b.a.com

a.com

而c.b.a.com则是不允许的。且两个页面若要通讯,则两者的主域必须相同。

上例中,主域就为 baidu.com。

window.name

在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name,每个页面对window.name都有读写的权限。

以上是对window.name的定义。试想如果有两个不同域的页面顺次被同一个窗口加载,那么对于这两个页面来说,两者就能共享window.name,从而实现通信。

如何顺次加载?利用window.location改变窗口的地址就可以办到这一点。

比如,http://example.com/a.html 完全加载后,修改window.name为指定值。然后通过window.location将窗口定向到 http://loliner.com/b.html,此时b.html中window.name的值就为上一个页面中设置的值。

window.name的值只能是一个字符串,最大2M,但对我们来说已经够用了。如果你要传递对象或数组,进行JSON格式化即可。

但是,虽然这样实现了数据通信,但是我们不能来回这样切来切去,那怎么办呢?这时候就可以利用 iframe + contentWindow 了。

我们可以在 b.html 页面添加一个隐藏的iframe,该iframe指向a.html,当a.html完全加载并修改了window.name之后,我们将iframe重新指向与b.html在同一个域名下的c.html,此时就可以通过 iframe 的 contentWindow 获取到 name 的值了。

完整代码如下:

H5跨域方式 window.postMessage

我们知道在同一个页面嵌入多个iframe,每个iframe的域都不一样时,虽然我们可以获取iframe的window对象,却不能访问其中的属性和方法。但H5的最新属性postMessage除外,那么我们是否可以在此利用这样的一个“漏洞”来进行跨域呢?

答案是可以的。

我们只需在iframe中设置onmessage监听,然后在父级页面中获取iframe的window对象,将父页面所要传递的信息通过window.postMessage发出即可。

完整代码如下:

首先要让iframe监听onmessage事件。

接下来则是在父页面中获取iframe的window对象并调用postMessage传递信息。

注意,此处的postMessage所发送的消息在低版本浏览器下只能为字符串,若要传递对象或数组,只能JSON格式化。

另外,第二个参数指的是域,表示你要将信息发送到哪个域,参数格式为协议+主机+端口,其实跟上面所说document.domain的值是一回事。

CORS

在所有以上提到的跨域方法中,不得不说都是利用了大大小小的漏洞来绕过同源策略。而无论如何进行绕过,有一点可以肯定的是,WEB开发当中确实需要跨域获取资源。

所以,W3C为我们制订了 CORS 跨域访问机制。CORS对于开发者来说最大的好处就是,无需考虑以什么样的方式绕过同源策略请求跨域资源,直接使用ajax即可。

那么谁去负责跨域的安全性呢?答案是由Server进行控制。

Server在接收到请求的时候,需判断请求来源,如果该来源合法,返回正常数据,同时需要在请求返回头response header中添加必要 CORS 字段。

对于浏览器来说,若该请求的返回头信息中,包含该 CORS 字段,那么浏览器就会正常读取返回的信息,否则,就会抛出No "Access-Control-Allow-Origin" header is present on the requested resource.禁止跨域异常。

上面所说到的CORS字段,分为必须与可选:

Access-Control-Allow-Origin(必须)

该服务器所允许跨域的源,如果为 * ,则表示允许所有源对该服务器进行请求。
发送请求的一方的域,必须包含在该值所指定的源内。

Access-Control-Allow-Credentials(可选)

表示是否允许发送cookie,该值为一个布尔值,默认为false。

Access-Control-Expose-Headers(可选)

获取response header中其他字段的值。

所以,简单的说,CORS 模式中的跨域请求其实与前端开发者已经没有太大的关系,只要Server端控制好接口数据,并按需写入CORS字段即可。

另外,CORS跨域请求可以分为简单请求与复杂请求。

简单请求

对于简单请求,浏览器直接发送CORS请求即可,跟上面所说流程一致。

HEAD、GET、POST都属于简单请求。
复杂请求

对于复杂请求,则需要首先发出预检请求,判断是否可以跨域,然后再发送真实请求。

PUT和DELETE,或Content-Type字段类型为application/json的都属于复杂请求。

就目前来说,JSONP 及 CORS 算是最常用的跨域形式了,也能满足我们的绝大部分需求。

相对于JSONP,CORS W3C规定的标准跨域方式,功能更强大,安全性也更好。

JSONP只支持GET请求,而 CORS 支持多种请求。

JSONP 没有域的概念,CORS 则有精确的指定哪些域可以获取资源。

CORS 将域的安全性管理完全交给Server管理,更加安全。

Flash跨域

Flash跨域也有多种形式,此处只介绍最常用的 crossdomain.xml 策略文件 模式及allowDomain 权限授予。

corssdomain.xml 跨域策略文件

与 CORS 复杂请求一样,Flash在进行跨域请求时,默认首先会发送预检请求,判断本域是否合法。该预检请求会去跨域请求的根目录获取 corssdomain.xml 文件,该文件包含了跨域策略信息。比如最重要的一点,就是告诉Flash哪些域可以跨域请求该服务器。

举个栗子,http://baidu.com/a.html下有某swf文件要向http://loliner.com/请求资源。此时会经过如下步骤:

Flash发现请求需要跨域,则首先请求http://loliner.com/crossdomai...文件;

若crossdomain.xml文件能正常返回,则分析其中的策略,查看本域是否合法;

若本域合法,则发送跨域请求;若不合法,则直接封杀请求。

此处注意,如果本域非法,Flash就会直接封杀了请求,那么我们在浏览器控制台是捕获不到该请求的,因为就没发出去。

那么Flash是怎么判断本域是否合法的呢?我们先来看一下一个最简单的corssdomain.xml文件结构。

所有的 crossdomain.xml 都以 作为根节点,里面的每一个都为一个策略。

其中,键值 domain 表示允许跨域的源,此处就跟 CORS 的 Access-Control-Allow-Origin 字段一样了。

而 secure ,则表示请求是否以加密进行传输。如果 corssdomain.xml 文件是从 https 协议下加载的,那么 secure 默认为 true。此时Flash若发现本域为非 https 协议,纵使 domain 合法,也会封杀请求。如果secure为false,则表明Flash可以发送非https加密过的请求。

Security.allowDomain 跨域权限授予

如果说介绍 crossdomain.xml 文件时我们是以 Client 端为角度的,那么介绍 Security.allowDomain 则必须以 Server 作为角度。

你可能会遇到如下情形,开发了多个swf,它们之间相互依赖,但以不同的域发布到网上。此时你只希望某些特定的域才有权限去修改或调用该swf中的属性及方法。那么此时,你就需要用到allowDomain方法对你所允许的域进行授权了。

以下是 allowDomain 的描述:

允许指定的域中的 SWF 文件访问调用了此方法的 SWF 文件中的对象和变量。

再举个栗子,http://a.com/a.swf 需要调用及修改 http://b.com/b.swf 中的属性及方法。
那么,就必须在b.swf中调用 Security.allowDomain("a.com")以允许a.com域对自己进行访问。

另外,要注意非常重要的一点,Security.allowDomain跨域权限授予是不对称的。

也就是说,在上面的栗子中,只允许a.swf访问b.swf,但b.swf却不能够访问a.swf。
如果非要这样做,那么就在a.swf中对b.com进行权限授予。

其次,对于HTTPS来说,即使调用了该方法,若试图利用在HTTP下的swf去修改HTTPS下的swf,此时也是非法的。因为这本身就不安全。

如果非要这样做,可以让HTTPS下的swf调用Security.allowInsecureDomain()对HTTP域进行权限授予

跨域方式对比

反观 Flash 跨域与H5 CORS 跨域,虽然两者在形式上有所不同,但本质上都向着以下两个特点靠拢:

先询问,后请求;

安全性靠Server端来维护。

对于 CORS 简单请求来说,浏览器是不会进行预检请求发送的,这样一个请求搞定所有的事,却不一定完全合理。因为对于浏览器来说,我在没有知道Server是否认为我的请求合法前,就已经抛出了大量的查询数据。这就有可能造成数据传输的冗余。

另外,如果由于开发过程不当,频繁发送不合法的跨域请求,本身就是一个资源的浪费。

所以,才需要到复杂请求。

而对于 Flash crossdomain.xml 这种方式(与 CORS 复杂请求类似),就避免了频繁发送不合法的跨域请求,因为在crossdomain.xml返回之前,Flash是不会发送任何跨域请求,直接在本地就将其封杀。同时crossdomain.xml并非每次跨域前都会请求,其有一个有效期。

但若我本身只需请求一次数据,但Server由于业务繁重却给我返回一个庞大的crossdomain.xml,这反而又显得不合理了。

文章来源:http://mp.weixin.qq.com/s/_KA...

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

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

相关文章

  • 前端培训-中级阶段(11、12)- 跨域请求原理以及实现(2019-08-22期)

    摘要:上节我们讲了同源策略,这节我们讲讲如何跨域。当这些从的脚本执行出错,因为违背了同源策略为了保证用户信息不被泄露,错误信息不会显示出来,取而代之只会返回一个。 前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每...

    binaryTree 评论0 收藏0
  • 彻底弄懂跨域问题

    摘要:用于告知浏览器可以将预先检查请求返回结果缓存的时间,在缓存有效期内,浏览器会使用缓存的预先检查结果判断是否发送跨域请求。 跨域,老生常谈的问题 简述 作为一只前端菜鸟,跨域方面只懂得JSONP和CORS,并未曾深入了解。但随着春招越来越近,就算是菜鸟也要猛振翅膀。近几日仔细研究了跨域问题,写下这篇文章,希望对开发者们有所帮助。在读本文前,希望您对以下知识略有了解。 浏览器同源策略 n...

    rose 评论0 收藏0
  • 前端常见跨域解决方案(全)

    摘要:需注意的是由于同源策略的限制,所读取的为跨域请求接口所在域的,而非当前页。目前,所有浏览器都支持该功能需要使用对象来支持,也已经成为主流的跨域解决方案。反向代理接口跨域跨域原理同源策略是浏览器的安全策略,不是协议的一部分。 什么是跨域? 跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。 广义的跨域: 1.) 资源跳转: A链接、重定向、表单提交 2.) 资源...

    canger 评论0 收藏0
  • 彻底弄懂跨域问题

    摘要:浏览器同源策略我们为何要研究跨域问题因为浏览器的同源策略规定某域下的客户端在没明确授权的情况下,不能读写另一个域的资源。 跨域,老生常谈的问题 简述 作为一只前端菜鸟,跨域方面只懂得JSONP和CORS,并未曾深入了解。但随着春招越来越近,就算是菜鸟也要猛振翅膀。近几日仔细研究了跨域问题,写下这篇文章,希望对开发者们有所帮助。在读本文前,希望您对以下知识略有了解。 浏览器同源策略 n...

    CoorChice 评论0 收藏0
  • 20K前端大佬面试(关于如何回答ajax跨域问题)

    摘要:在接触前端开发起,跨域这个词就一直以很高的频率在我们学习工作中重复出现,最近在工作中遇到了跨域的相关问题,这里我把它总结记录一下。 在接触前端开发起,跨域这个词就一直以很高的频率在我们学习工作中重复出现,最近在工作中遇到了跨域的相关问题,这里我把它总结记录一下。关于跨域,有N种类型,现在我只专注于ajax请求跨域(ajax跨域只是属于浏览器同源策略中的一部分,其它的这里不做介绍),内容...

    Yangyang 评论0 收藏0

发表评论

0条评论

Coding01

|高级讲师

TA的文章

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