一、同源策略
在总结各种跨域问题之前,我们先来了解一下浏览器的同源策略。
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说 Web 是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
它的核心就在于它认为自任何站点装载的信赖内容是不安全的。当被浏览器半信半疑的脚本运行在沙箱时,它们应该只被允许访问来自同一站点的资源,而不是那些来自其它站点可能怀有恶意的资源。
所谓同源是指:域名、协议、端口相同。
同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。
因为存在浏览器同源策略,所以才会有跨域问题。那么浏览器是出于何种原因会有跨域的限制呢。其实不难想到,跨域限制主要的目的就是为了用户的上网安全。
如果浏览器没有同源策略,会存在什么样的安全问题呢。下面从 DOM 同源策略和 XMLHttpRequest 同源策略来举例说明:
1.如果没有 DOM 同源策略,也就是说不同域的 iframe 之间可以相互访问,那么黑客可以这样进行攻击:
· 做一个假网站,里面用 iframe 嵌套一个银行网站 http://mybank.com。
· 把 iframe 宽高啥的调整到页面全部,这样用户进来除了域名,别的部分和银行的网站没有任何差别。
· 这时如果用户输入账号密码,我们的主网站可以跨域访问到 http://mybank.com 的 dom 节点,就可以拿到用户的账户密码了。
2.如果 XMLHttpRequest 同源策略,那么黑客可以进行 CSRF(跨站请求伪造) 攻击:
· 用户登录了自己的银行页面 http://mybank.com,http://mybank.com 向用户的 cookie 中添加用户标识。
· 用户浏览了恶意页面 http://evil.com,执行了页面中的恶意 AJAX 请求代码。
· http://evil.com 向 http://mybank.com 发起 AJAX HTTP 请求,请求会默认把 http://mybank.com 对应 cookie 也同时发送过去。
· 银行页面从发送的 cookie 中提取用户标识,验证用户无误,response 中返回请求数据。此时数据就泄露了。
· 而且由于 Ajax 在后台执行,用户无法感知这一过程。
因此,有了浏览器同源策略,我们才能更安全的上网。
下表是相对于 http://www.laixiangran.cn/home/index.html 的同源检测结果:
另外,同源策略又分为以下两种:
· DOM 同源策略:禁止对不同源页面 DOM 进行操作。这里主要场景是 iframe 跨域的情况,不同域名的 iframe 是限制互相访问的。
· XMLHttpRequest 同源策略:禁止使用 XHR 对象向不同源的服务器地址发起 HTTP 请求。
受到同源限制:
1)无法读取不同源的 Cookie、LocalStorage 和 IndexDB 。
2)无法获得不同源的DOM 。
3)不能向不同源的服务器发送ajax请求。
不受同源限制:
在浏览器中,<script>、<img>、<iframe>、<link>等标签都可以跨域加载资源,而不受同源策略的限制。
二、什么是跨域?
浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域
域名:
主域名不同 http://www.baidu.com/index.html –>http://www.sina.com/test.js
子域名不同 http://www.666.baidu.com/index.html –>http://www.555.baidu.com/test.js
域名和域名ip http://www.baidu.com/index.html –>http://180.149.132.47/test.js
端口:
http://www.baidu.com:8080/index.html–> http://www.baidu.com:8081/test.js
协议:
http://www.baidu.com:8080/index.html–> https://www.baidu.com:8080/test.js
备注:
1、端口和协议的不同,只能通过后台来解决
2、localhost和127.0.0.1虽然都指向本机,但也属于跨域
常用的跨域方式有2种:CROS(跨域资源共享Cross-Origin Resource Sharing)、JSONP
· CROS:服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。该设置只被现代浏览器支持
· JSONP:实际是对跨域行为的hack手段,实现原理和加载js是一个道理,所以只能实现get请求的jsonp.
在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的。但是,在页面上引入不同域上的js脚本文件却是可以的,jsonp正是利用这个特性来实现的。
CORS和JSONP对比
CORS与JSONP相比,无疑更为先进、方便和可靠。
1、JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。(类似往页面添加一个script标签,通过src属性去触发对指定地址的请求,故只能是Get请求)
2、使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。
3、JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS)。
三、跨域的几种方式和解决方案
1.CORS 跨域
CORS(Cross-origin resource sharing,跨域资源共享)是一个 W3C 标准,定义了在必须访问跨域资源时,浏览器与服务器应该如何沟通。CORS 背后的基本思想,就是使用自定义的 HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
CORS 需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE 浏览器不能低于 IE10。
整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨源通信。
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。
只要同时满足以下两大条件,就属于简单请求。
· 请求方法是以下三种方法之一:
HEAD
GET
POST
· HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
· Content-Type:只限于三个值 application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不同时满足上面两个条件,就属于非简单请求。
浏览器对这两种请求的处理,是不一样的。
简单请求
· 在请求中需要附加一个额外的 Origin 头部,其中包含请求页面的源信息(协议、域名和端口),以便服务器根据这个头部信息来决定是否给予响应。例如:Origin: http://www.laixiangran.cn
· 如果服务器认为这个请求可以接受,就在 Access-Control-Allow-Origin 头部中回发相同的源信息(如果是公共资源,可以回发 * )。例如:Access-Control-Allow-Origin:http://www.laixiangran.cn
· 没有这个头部或者有这个头部但源信息不匹配,浏览器就会驳回请求。正常情况下,浏览器会处理请求。注意,请求和响应都不包含 cookie 信息。
· 如果需要包含 cookie 信息,ajax 请求需要设置 xhr 的属性 withCredentials 为 true,服务器需要设置响应头部 Access-Control-Allow-Credentials: true。
非简单请求
浏览器在发送真正的请求之前,会先发送一个 Preflight 请求给服务器,这种请求使用 OPTIONS 方法,发送下列头部:
· Origin:与简单的请求相同。
· Access-Control-Request-Method: 请求自身使用的方法。
· Access-Control-Request-Headers: (可选)自定义的头部信息,多个头部以逗号分隔。
例如:
Origin: http://www.laixiangran.cn
Access-Control-Request-Method: POST
Access-Control-Request-Headers: NCZ
发送这个请求后,服务器可以决定是否允许这种类型的请求。服务器通过在响应中发送如下头部与浏览器进行沟通:
· Access-Control-Allow-Origin:与简单的请求相同。
· Access-Control-Allow-Methods: 允许的方法,多个方法以逗号分隔。
· Access-Control-Allow-Headers: 允许的头部,多个方法以逗号分隔。
· Access-Control-Max-Age: 应该将这个 Preflight 请求缓存多长时间(以秒表示)。
例如:
Access-Control-Allow-Origin: http://www.laixiangran.cn
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: NCZ
Access-Control-Max-Age: 1728000
一旦服务器通过 Preflight 请求允许该请求之后,以后每次浏览器正常的 CORS 请求,就都跟简单请求一样了。
优点
· CORS 通信与同源的 AJAX 通信没有差别,代码完全一样,容易维护。
· 支持所有类型的 HTTP 请求。
缺点
· 存在兼容性问题,特别是 IE10 以下的浏览器。
· 第一次发送非简单请求时会多一次请求。
2.JSONP 跨域
JSONP(JSON with Padding)是数据格式JSON的一种“使用模式”,可以让网页从别的网域要数据。根据 XmlHttpRequest 对象受到同源策略的影响,而利用 <script>元素的这个开放策略,网页可以得到从其他来源动态产生的JSON数据,而这种使用模式就是所谓的 JSONP。用JSONP抓到的数据并不是JSON,而是任意的JavaScript,用 JavaScript解释器运行而不是用JSON解析器解析。所有,通过Chrome查看所有JSONP发送的Get请求都是js类型,而非XHR。
由于 script 标签不受浏览器同源策略的影响,允许跨域引用资源。因此可以通过动态创建 script 标签,然后利用 src 属性进行跨域,这也就是 JSONP 跨域的基本原理。
直接通过下面的例子来说明 JSONP 实现跨域的流程:
// 1. 定义一个 回调函数 handleResponse 用来接收返回的数据 function handleResponse(data) { console.log(data); }; // 2. 动态创建一个 script 标签,并且告诉后端回调函数名叫 handleResponse var body = document.getElementsByTagName('body')[0]; var script = document.gerElement('script'); script.src = 'http://www.laixiangran.cn/json?callback=handleResponse'; body.appendChild(script); // 3. 通过 script.src 请求 `http://www.laixiangran.cn/json?callback=handleResponse`, // 4. 后端能够识别这样的 URL 格式并处理该请求,然后返回 handleResponse({"name": "laixiangran"}) 给浏览器 // 5. 浏览器在接收到 handleResponse({"name": "laixiangran"}) 之后立即执行 ,也就是执行 handleResponse 方法,获得后端返回的数据,这样就完成一次跨域请求了。
优点
· 使用简便,没有兼容性问题,目前最流行的一种跨域方法。
缺点
· 只支持 GET 请求。
· 由于是从其它域中加载代码执行,因此如果其他域不安全,很可能会在响应中夹带一些恶意代码。
· 要确定 JSONP 请求是否失败并不容易。虽然 HTML5 给 script 标签新增了一个 onerror 事件处理程序,但是存在兼容性问题。
3.图像ping或script标签跨域
由于 img 标签不受浏览器同源策略的影响,允许跨域引用资源。因此可以通过 img 标签的 src 属性进行跨域,这也就是图像 Ping 跨域的基本原理。
直接通过下面的例子来说明图像 Ping 实现跨域的流程:
var img = new Image(); // 通过 onload 及 onerror 事件可以知道响应是什么时候接收到的,但是不能获取响应文本 img.onload = img.onerror = function() { console.log("Done!"); } // 请求数据通过查询字符串形式发送 img.src = 'http://www.laixiangran.cn/test?name=laixiangran';
优点
· 图片ping常用于跟踪用户点击页面或动态广告曝光次数。
· script标签可以得到从其他来源数据,这也是JSONP依赖的根据。
缺点
· 只支持 GET 请求。
· 只能浏览器与服务器的单向通信,因为浏览器不能访问服务器的响应文本。
4.服务器代理
跨域请求报错归根结底是浏览器禁止使用XHR对象向不同源的服务器地址发起HTTP请求。如果是服务器跨域向多个不同的服务器发送请求就不会有跨域问题存在。因此,我们可以让浏览器只向一个服务器方式请求,让这个服务器代替浏览器去不同的服务器上请求资源再返回给浏览器。这个服务器就是代理服务器了。
例如 www.baidu.com/index.html需要调用www.sina.com/server.php,可以写一个接口www.baidu.com/server.php,由这个接口在后端去调用www.sina.com/server.php并拿到返回值,然后再返回给index.html
整个流程就是这样:DomainA客户端(浏览器) ==> DomainA服务器 ==> DomainB服务器 ==> DomainA客户端(浏览器)
服务器代理是万能的。
下面推荐一个常用代理服务器nginx。
Nginx (engine x) 是一款轻量级的Web 服务器 、反向代理服务器及电子邮件(IMAP/POP3)代理服务器。
把ui所在的服务器和跨域服务器都用nginx代理转发,浏览器访问nginx,nginx到ui服务获取ui,再把ui下载到浏览器,浏览器发起ui中的URL,该URL为Nginx封装后的跨域服务器的URL或ui服务器的URL,该URL到达Nginx之后,会被转发到跨域服务器或ui服务器,请求处理完毕后,会通过Nginx中转返回给浏览器。暴露出来的或者浏览器所发起的url都是nginx的url,nginx去跨域服务器和ui服务器获取响应,返给浏览器,这样就没有跨域问题了。
5.document.domain 跨域
分为两种,一种xhr不能访问不同源的文档,另一种是不同window之间不能进行交互操作;
document.domain主要是解决第二种情况,且只能适用于主域相同子域不同的情况;
document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。例如:a.b.example.com中某个文档的document.domain可以设成a.b.example.com、b.example.com 、example.com中的任意一个,但是不可以设成c.a.b.example.com,因为这是当前域的子域,也不可以设成baidu.com,因为主域已经不相同了。
对于主域名相同,而子域名不同的情况,可以使用 document.domain 来跨域。这种方式非常适用于 iframe 跨域的情况。
比如,有一个页面,它的地址是 http://www.laixiangran.cn/a.html,在这个页面里面有一个 iframe,它的 src 是 http://laixiangran.cn/b.html。很显然,这个页面与它里面的 iframe 框架是不同域的,所以我们是无法通过在页面中书写 js 代码来获取 iframe 中的东西的。
这个时候,document.domain 就可以派上用场了,我们只要把 http://www.laixiangran.cn/a.html 和 http://laixiangran.cn/b.html 这两个页面的 document.domain 都设成相同的域名就可以了。但要注意的是,document.domain 的设置是有限制的,我们只能把 document.domain 设置成自身或更高一级的父域,且主域必须相同。例如:a.b.laixiangran.cn 中某个文档的 document.domain 可以设成 a.b.laixiangran.cn、b.laixiangran.cn 、laixiangran.cn 中的任意一个,但是不可以设成 c.a.b.laixiangran.cn ,因为这是当前域的子域,也不可以设成 baidu.com,因为主域已经不相同了。
例如,在页面 http://www.laixiangran.cn/a.html 中设置document.domain:
<iframe src="http://laixiangran.cn/b.html" id="myIframe" onload="test()"> <script> document.domain = 'laixiangran.cn'; // 设置成主域 function test() { console.log(document.getElementById('myIframe').contentWindow); } </script>
在页面 http://laixiangran.cn/b.html 中也设置 document.domain,而且这也是必须的,虽然这个文档的 domain 就是 laixiangran.cn,但是还是必须显式地设置 document.domain 的值:
<script> document.domain = 'laixiangran.cn'; // document.domain 设置成与主页面相同 </script>
这样,http://www.laixiangran.cn/a.html 就可以通过 js 访问到 http://laixiangran.cn/b.html 中的各种属性和对象了。
兼容性:所有浏览器都支持;
优点:
· 可以实现不同window之间的相互访问和操作;
缺点:
· 只适用于父子window之间的通信,不能用于xhr;
· 只能在主域相同且子域不同的情况下使用;
6.window.name 跨域
window 对象有个 name 属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面(不管是相同域的页面还是不同域的页面)都是共享一个 window.name 的,每个页面对 window.name 都有读写的权限,window.name 是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。
比如:我们在任意一个页面输入
window.name = "My window's name"; setTimeout(function(){ window.location.href = "http://damonare.cn/"; },1000)
进入damonare.cn页面后我们再检测再检测 window.name :
window.name; // My window's name
可以看到,如果在一个标签里面跳转网页的话,我们的 window.name 是不会改变的。
基于这个思想,我们可以在某个页面设置好 window.name 的值,然后跳转到另外一个页面。在这个页面中就可以获取到我们刚刚设置的 window.name 了。
由于安全原因,浏览器始终会保持 window.name 是string 类型。
同样这个方法也可以应用到和iframe的交互来:
比如:我的页面(http://damonare.cn/index.html)中内嵌了一个iframe:
<iframe id="iframe" src="http://www.google.com/iframe.html"></iframe>
在 iframe.html 中设置好了 window.name 为我们要传递的字符串。
我们在 index.html 中写了下面的代码:
var iframe = document.getElementById('iframe'); var data = ''; iframe.onload = function() { data = iframe.contentWindow.name; }; Boom!报错!肯定的,因为两个页面不同源嘛,想要解决这个问题可以这样干: var iframe = document.getElementById('iframe'); var data = ''; iframe.onload = function() { iframe.onload = function(){ data = iframe.contentWindow.name; } iframe.src = 'about:blank'; };
或者将里面的 about:blank 替换成某个同源页面(about:blank,javascript: 和 data: 中的内容,继承了载入他们的页面的源。)
这种方法与 document.domain 方法相比,放宽了域名后缀要相同的限制,可以从任意页面获取 string 类型的数据。
通过下面的例子介绍如何通过 window.name 来跨域获取数据的。
页面 http://www.laixiangran.cn/a.html 的代码:
<iframe src="http://laixiangran.cn/b.html" id="myIframe" onload="test()" style="display: none;"> <script> // 2. iframe载入 "http://laixiangran.cn/b.html 页面后会执行该函数 function test() { var iframe = document.getElementById('myIframe'); // 重置 iframe 的 onload 事件程序, // 此时经过后面代码重置 src 之后, // http://www.laixiangran.cn/a.html 页面与该 iframe 在同一个源了,可以相互访问了 iframe.onload = function() { var data = iframe.contentWindow.name; // 4. 获取 iframe 里的 window.name console.log(data); // hello world! }; // 3. 重置一个与 http://www.laixiangran.cn/a.html 页面同源的页面 iframe.src = 'http://www.laixiangran.cn/c.html'; } </script>
页面 http://laixiangran.cn/b.html 的代码:
<script type="text/javascript"> // 1. 给当前的 window.name 设置一个 http://www.laixiangran.cn/a.html 页面想要得到的数据值 window.name = "hello world!"; </script>
关键点:window.name在页面的生命周期里共享一个window.name;
兼容性:所有浏览器都支持;
优点:
· 最简单的利用了浏览器的特性来做到不同域之间的数据传递;
· 不需要前端和后端的特殊配制;
缺点:
· 大小限制:window.name最大size是2M左右,不同浏览器中会有不同约定;
· 安全性:当前页面所有window都可以修改,很不安全;
· 数据类型:传递数据只能限于字符串,如果是对象或者其他会自动被转化为字符串,如下;
使用方式:修改window.name的值即可;
7.location.hash 跨域
因为父窗口可以对iframe进行URL读写,iframe也可以读写父窗口的URL,URL有一部分被称为hash,就是#号及其后面的字符,它一般用于浏览器锚点定位,Server端并不关心这部分,应该说HTTP请求过程中不会携带hash,所以这部分的修改不会产生HTTP请求,但是会产生浏览器历史记录。此方法的原理就是改变URL的hash部分来进行双向通信。每个window通过改变其他 window的location来发送消息(由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于父窗口域名下的一个代理iframe),并通过监听自己的URL的变化来接收消息。这个方式的通信会造成一些不必要的浏览器历史记录,而且有些浏览器不支持onhashchange事件,需要轮询来获知URL的改变,最后,这样做也存在缺点,诸如数据直接暴露在了url中,数据容量和类型都有限等。下面举例说明:
假如父页面是baidu.com/a.html,iframe嵌入的页面为google.com/b.html(此处省略了域名等url属性),要实现此两个页面间的通信可以通过以下方法。
a.html传送数据到b.html
a.html下修改iframe的src为google.com/b.html#paco
b.html监听到url发生变化,触发相应操作
b.html传送数据到a.html,由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于父窗口域名下的一个代理iframe
b.html下创建一个隐藏的iframe,此iframe的src是baidu.com域下的,并挂上要传送的hash数据,如src=”http://www.baidu.com/proxy.html#data"
proxy.html监听到url发生变化,修改a.html的url(因为a.html和proxy.html同域,所以proxy.html可修改a.html的url hash)
a.html监听到url发生变化,触发相应操作
b.html页面的关键代码如下:
try { parent.location.hash = 'data'; } catch (e) { // ie、chrome的安全机制无法修改parent.location.hash, var ifrproxy = document.createElement('iframe'); ifrproxy.style.display = 'none'; ifrproxy.src = "http://www.baidu.com/proxy.html#data"; document.body.appendChild(ifrproxy); }
proxy.html页面的关键代码如下 :
//因为parent.parent(即baidu.com/a.html)和baidu.com/proxy.html属于同一个域,所以可以改变其location.hash的值 parent.parent.location.hash = self.location.hash.substring(1);
8.postMessage 跨域
HTML5引入了一个全新的API,跨文档通信 API(Cross-document messaging)。这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。a就可以把它的LocalStorage,发送给b,b也可以把自己的LocalStorage发给a。
window.postMessage(message, targetOrigin, [transfer]),有三个参数:
· message是向目标窗口发送的数据;
· targetOrigin属性来指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个URI(或者说是发送消息的目标域名);
· transfer可选参数,是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
另外消息的接收方必须有监听事件,否则发送消息时就会报错。The target origin provided ('http://localhost:8080') does not match the recipient window's origin ('http://localhost:63343').
window.addEventListener("message",onmessage);onmessage接收到的message事件包含三个属性:
· data:从其他 window 中传递过来的数据。
· origin:调用 postMessage 时消息发送方窗口的 origin 。请注意,这个origin不能保证是该窗口的当前或未来origin,因为postMessage被调用后可能被导航到不同的位置。
· source:对发送消息的窗口对象的引用; 您可以使用此来在具有不同origin的两个窗口之间建立双向通信。
例子:我在a页面执行
var popup = window.open('http://localhost:3000', 'title');
popup.postMessage('Hello World!', 'http://localhost:3000');
同时在http://localhost:3000的页面里监听message事件:
window.onload=function () { window.addEventListener("message",onmessage); } function onmessage(event) { if(event.origin=="http://localhost:63343"){//http://localhost:63343是发送方a的域名 console.log(event.data);//'Hello World!' } console.log(event.data);//'Hello World!' }
兼容性:移动端可以放心用,但是pc端需要做降级处理
优点:
· 不需要后端介入就可以做到跨域,一个函数外加两个参数(请求url,发送数据)就可以搞定;
· 移动端兼容性好;
缺点 :
· 无法做到一对一的传递方式:监听中需要做很多消息的识别,由于postMessage发出的消息对于同一个页面的不同功能相当于一个广播的过程,该页面的所有onmessage都会收到,所以需要做消息的判断;
安全性问题:三方可以通过截获,注入html或者脚本的形式监听到消息,从而能够做到篡改的效果,所以在postMessage和onmessage中一定要做好这方面的限制;
发送的数据会通过结构化克隆算法进行序列化,所以只有满足该算法要求的参数才能够被解析,否则会报错,如function就不能当作参数进行传递;
使用方式:通信的函数,sendMessage负责发送消息,bindEvent负责消息的监听并处理,可以通过代码来做一个大致了解;
Storage.prototype.sendMessage_ = function(type, params, fn) { if (this.topWindow) { this.handleCookie_(type, params, fn); return; } var eventId = this.addToQueue_(fn, type); var storageIframe = document.getElementById('mip-storage-iframe'); var element = document.createElement("a"); element.href = this.origin; var origin = element.href.slice(0, element.href.indexOf(element.pathname) + 1); storageIframe.contentWindow.postMessage({ type: type, params: params, eventId: eventId }, origin); } Storage.prototype.bindEvent_ = function() { window.onmessage = function (res) { // 判断消息来源 if (window == res.source.window.parent && res.data.type === this.messageType.RES && window.location.href.match(res.origin.host).length > 0) { var fn = this.eventQueue[res.data.eventId]; fn && fn(); delete this.eventQueue[res.data.eventId]; // reset id var isEmpty = true; for (var t in this.eventQueue) { isEmpty = false; } if (isEmpty) { this.id = 0; } } }.bind(this); }
参考网址:
如何解决跨域问题:https://blog.csdn.net/tjcjava/article/details/76468225
9种跨域解决方案优缺点:https://blog.csdn.net/qq_36140085/article/details/81606508
8种方式实现跨域或请求:https://blog.csdn.net/ligang2585116/article/details/73072868
跨域问题汇总:https://segmentfault.com/a/1190000012158485
前端跨域问题整理:http://blog.damonare.cn/2016/12/01/前端跨域问题整理/
JS常见的跨域问题分析:https://www.cnblogs.com/2050/p/3191744.html
转载请注明: ITTXX.CN--分享互联网 » 关于网站跨域问题分析和讲解
最后更新:2019-02-19 09:33:12