分类总结跨域解决方案应用

548 阅读4分钟

前言

        笔者之前用过Nginx、Node.js、JSONP方法解决过前端跨域,最近项目上要公开一个方法给其他域下的页面调用,因此又接触到跨域,借此机会在这里分AJAX方面的跨域和操纵JS交互脚本方面的跨域这两个维度来进行简单总结。本文章是笔者第一篇掘金文章,算是对自己的监督,各位多多指教。

正文

1. 什么是跨域?

       广义上的跨域是指一个域下的文档或者脚本试图请求另一个域下的资源。(ps:只要协议、主机、端口三者中任何一个不同,都被当作不同的域哦。)
        常见的跨域行为:

        a)、资源跳转:<a>标签跳转链接、重定向、表单提交;

        b)、资源请求,<link>、<script>、<img>、<frame>的url请求,@font-face()的引用

        c)、JS发起的脚本请求、DOM和JS对象的跨域操作

2. 同源策略

        只有当协议、主机、端口三者都相同,才算同源。

        主要基于安全考虑,浏览器设置了同源策略,如果“非同源”,浏览器会限制:

       a)、网络方面:AJAX不能发送;

       b)、DOM和JS对象无法获取、操作;

       c)、Cookies、localStorage、IndexDB无法读取;

       笔者将b、c点统称为操纵JS脚本方面的跨域,a点位AJAX的跨域。

3.AJAX方面的跨域解决方案

(1)document.domain + ifame

        原理:两个页面强制通过JS设置document.domain为基础主域,使得二者同域,实现跨域。

        缺点:因document.domain设置有限制,因此只适用于主域相同,子域不同的场景。

        实现:

  • 父窗口(http://mainDomain.com/a.html):

<iframe src="http://child.mainDomain.com/b.html"></iframe>

<script>

    document.domain = 'mainDomain.com';      // 设置主域         

    var publicKey = 'value';       

</script>

  • 子窗口(http://child.mainDomain.com/b.html):

<iframe src="http://child.mainDomain.com/b.html"></iframe>

<script>

    document.domain = 'mainDomain.com'; // 设置主域

    console.log(parent.publicKey); // 成功访问父窗口的publicKey值

</script>

(2)document.hash+ ifame

        原理:父窗口可以对iframe的src进行读写,子窗口嵌套父窗口同域的页面,通过parent.parent.callback访问父窗口JS,而服务器会忽视url中#后面的字符,通过浏览器的hashchange事件监控到location.hash的变化。这样就可以实现iframe之间的通讯。

        例子: 实现不同域下的 a.html 和 b.html 之间的通信。

         

        关键代码:

  • a.html

// 控制b.html的src并传值
document.getElementById('iframe').src = 'http:domain2.com/b.html#msg=hello';
// 对外暴露回调函数window.oncallback = function(){  
    // ... 回调函数
}
  • b.html

window.onhashchange = function(e) {       
    // location.hash,处理数据,通过proxy.html执行回调      
    document.getElementById('proxy').src = 'http:domain1.com/proxy#data=123';
}
  • proxy.html

window.onhashchange = function(e) {
    parent.parent.oncallback(loaction.hash)
}

(3)通过parent.parent.oncallback,通过嵌套iframe的代理窗口进行跨域

        原理和第2点类似,这一种比较简易优雅,通过窗口url的参数来通信。实现如下图:


(4)postMessage跨域

    postMessage是HTML5 XMLHttpRequest Level 2中的API,可以安全地实现跨域

        方法:otherWindow.postMessage(message, targetOrigin, [transfer])

        otherWindow: 目标窗口;

        message: 向发送给其他window的数据(基本类型和对象,部分浏览器不支持对象);

        targetOrigin:协议+主机+端口号,也可以设置为"*",目标源的限制

(5)window.name

        原理:同一个窗口的window.name属性会一直保存,刷新页面后仍保存,可以借此共享数据。

4. AJAX方面的跨域解决方案

(1)JSONP

        原理:浏览器同源策略没有限制<script>的跨域请求,基于这个原理,我们可以通过动态创建script,请求不同域的服务器,服务器返回回调函数来实现跨域通讯。

       原生实现:


(2)反向代理,例如Nginx、Node.js等后端服务器代理

       原理:浏览器有同源策略限制AJAX请求,但服务器与服务器之间通讯没有限制,所以可以通过同源的代理服务器接受AJAX请求,从而实现跨域

(3)通过CORS跨域

        实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

总结

        本文章把跨域分两大类来进行总结,总结要点式概括,有些方法只是一笔带过,又需要的同学可以查看掘金的其他详细类文章。


参考文章: