摘要:在所有以上提到的跨域方法中,不得不说都是利用了大大小小的漏洞来绕过同源策略。对于开发者来说最大的好处就是,无需考虑以什么样的方式绕过同源策略请求跨域资源,直接使用即可。
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
摘要:上节我们讲了同源策略,这节我们讲讲如何跨域。当这些从的脚本执行出错,因为违背了同源策略为了保证用户信息不被泄露,错误信息不会显示出来,取而代之只会返回一个。 前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每...
摘要:需注意的是由于同源策略的限制,所读取的为跨域请求接口所在域的,而非当前页。目前,所有浏览器都支持该功能需要使用对象来支持,也已经成为主流的跨域解决方案。反向代理接口跨域跨域原理同源策略是浏览器的安全策略,不是协议的一部分。 什么是跨域? 跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。 广义的跨域: 1.) 资源跳转: A链接、重定向、表单提交 2.) 资源...
摘要:在接触前端开发起,跨域这个词就一直以很高的频率在我们学习工作中重复出现,最近在工作中遇到了跨域的相关问题,这里我把它总结记录一下。 在接触前端开发起,跨域这个词就一直以很高的频率在我们学习工作中重复出现,最近在工作中遇到了跨域的相关问题,这里我把它总结记录一下。关于跨域,有N种类型,现在我只专注于ajax请求跨域(ajax跨域只是属于浏览器同源策略中的一部分,其它的这里不做介绍),内容...
阅读 3470·2021-11-12 10:36
阅读 2838·2021-09-22 15:35
阅读 2792·2021-09-04 16:41
阅读 1145·2019-08-30 15:55
阅读 3561·2019-08-29 18:43
阅读 2056·2019-08-23 18:24
阅读 1357·2019-08-23 18:10
阅读 1904·2019-08-23 11:31