js实现跨域的多种方法


Posted in Javascript onDecember 25, 2015

从域说起

域: 域是WIN2K网络系统的安全性边界。我们知道一个计算机网最基本的单元就是“域”,这一点不是WIN2K所独有的,但活动目录可以贯穿一个或多个域。在独立的计算机上,域即指计算机本身,一个域可以分布在多个物理位置上,同时一个物理位置又可以划分不同网段为不同的域,每个域都有自己的安全策略以及它与其他域的信任关系。当多个域通过信任关系连接起来之后,活动目录可以被多个信任域域共享
域树:域树由多个域组成,这些域共享同一表结构和配置,形成一个连续的名字空间。树中的域通过信任关系连接起来,活动目录包含一个或多个域树。域树中的域是通过双向可传递信任关系连接在一起。由于这些信任关系是双向的而且是可传递的,因此在域树或树林中新创建的域可以立即与域树或树林中每个其他的域建立信任关系。这些信任关系允许单一登录过程,在域树或树林中的所有域上对用户进行身份验证,但这不一定意味着经过身份验证的用户在域树的所有域中都拥有相同的权利和权限。因为域是安全界限,所以必须在每个域的基础上为用户指派相应的权利和权限。
域树中的域层次越深级别越低,一个“.”代表一个层次。
如域zhidao.baidu.com(百度知道)就比 baidu.com(百度)这个域级别低,因为它有两个层次关系,而baidu.com只有一个层次。

何为跨域

默认情况下,,XHR 对象只能访问与包含它的页面位于同一个域中的资源。这种安全策略可以预防某些恶意行为。但是,实现合理的跨域请求对开发某些浏览器应用程序也是至关重要的。
只要协议、域名、端口有任何一个不同,都被当作是不同的域

比如在http://www.a.com/a.js 页面向以下页面发送一个ajax请求,以下是其请求结果及说明

js实现跨域的多种方法

对于端口和协议的不同,只能通过后台来解决。我们要解决的是域名不同的问题

如何跨域

(一) CORS(Cross-Origin Resource Sharing,跨源资源共享)

1.CORS(Cross-Origin Resource Sharing,跨源资源共享)是W3C 的一个工作草案,定义了在必须访问跨源资源时,浏览器与服务器应该如何沟通。CORS 背后的基本思想,就是使用自定义的HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
2.实现此功能非常简单,只需由服务器发送一个响应标头即可。

浏览器支持情况:

  • IE 8+
  • Firefox 3.5+
  • Opera 12+
  • Safari 4+
  • Chrome 3+

假设我们页面或者应用已在 http://www.a.com/ 上了,而我们打算从 http://www.b.com 请求提取数据。一般情况下,如果我们直接使用 AJAX 来请求将会失败,浏览器也会返回错误。
利用 CORS,http://www.b.com 只需添加一个标头,就可以允许来自 http://www.a.com 的请求。
下面是用php进行的设置,“*”号表示允许任何域向我们的服务端提交请求:

header{"Access-Control-Allow-Origin: *"}

CORS的兼容性写法

function createCORSRequest(method, url){
 var xhr = new XMLHttpRequest();
 //非IE浏览器
 if ("withCredentials" in xhr){
 xhr.open(method, url, true);
 //IE浏览器
 } else if (typeof XDomainRequest != "undefined"){
 vxhr = new XDomainRequest();
 xhr.open(method, url);
 } else {
 xhr = null;
 }
 return xhr;
 }
 var request = createCORSRequest("get", "http://www.somewhere-else.com/page/");
 if (request){
 request.onload = function(){
 //对request.responseText 进行处理
 };
 request.send();
 }

(二) JSONP(JSON with Padding 填充式JSON 或参数式JSON)

在js中,我们虽然不能直接用XMLHttpRequest请求不同域上的数据时,但是在页面上引入不同域上的js脚本文件却是可以的,jsonp正是利用这个特性来实现的

JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,而数据就是传入回调函数中的JSON数据。

例如:

<script type="text/javascript">
 function dosomething(jsondata){
 //处理获得的json数据
 }
</script>
<script src="http://example.com/data.php?callback=dosomething"></script>

首先第一个script便签定义了一个处理数据的函数;
然后第二个script标签载入一个js文件,http://example.com/data.php 是数据所在地址,但是因为是当做js来引入的,所以http://example.com/data.php 返回的必须是一个能执行的js文件;
最后js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入。所以php应该是这样的

<?php
$callback = $_GET['callback'];//得到回调函数名
$data = array('a','b','c');//要返回的数据
echo $callback.'('.json_encode($data).')';//输出
?>

最终,输出结果为:dosomething(['a','b','c']);
从上面可以看出jsonp是需要服务器端的页面进行相应的配合的。

JSONP的优缺点
优点:

它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;
能够直接访问响应文本,支持在浏览器与服务器之间双向通信
缺点:

JSONP 是从其他域中加载代码执行。如果其他域不安全,很可能会在响应中夹带一些恶意代码,而此时除了完全放弃JSONP 调用之外,没有办法追究。因此在使用不是你自己运维的Web 服务时,一定得保证它安全可靠。
它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
(三) window.name

window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。

这里有三个页面:

a.com/app.html:应用页面。
a.com/proxy.html:代理文件,一般是一个没有任何内容的html文件,需要和应用页面在同一域下。
b.com/data.html:应用页面需要获取数据的页面,可称为数据页面。

app.html

<iframe src="b.com/data.html" id="iframe"></iframe>
<script>
 var iframe = document.getElementById("iframe");
 iframe.src = "a.com/proxy.html";//这是一个与a.com/app.html同源的页面
 iframe.onload = function(){
 var data = iframe.contentWindow.name; //取到数据
 }

</script>

data.html

<script>
 // 这里是要传输的数据,大小一般为2M,IE和firefox下可以大至32M左右
 // 数据格式可以自定义,如json、字符串
 window.name = "数据"
</script>

iframe首先的地址是b.com/data.html,所以能取到window.name数据;
但是iframe现在跟app.html并不同源,app.html无法获取到数据,所以又将iframe的链接跳转至a.com/proxy.html这个代理页面,现在app.html跟iframe就同源了。

注意:iframe由b.com/data.html跳转到a.com/proxy.html页面,window.name的value是不变的

获取数据以后销毁这个iframe,释放内存;这也保证了安全(不被其他域frame js访问)

<script type="text/javascript">
 iframe.contentWindow.document.write('');
 iframe.contentWindow.close();
 document.body.removeChild(iframe);
</script>

(四) document.domain + iframe

对于主域相同而子域不同的例子,可以通过设置document.domain的办法来解决。
具体的做法是可以在http://www.a.com/a.html 和http://script.a.com/b.html 两个文件中分别设置document.domain = 'a.com',然后通过a.html文件中创建一个iframe,去控制iframe的contentDocument,这样两个js文件之间就可以“交互”了。
http://www.a.com/a.html页面

<iframe src="http://script.a.com/b.html" frameborder="0"></iframe>
<script>
 document.domain = 'a.com';
</script>

http://script.a.com/b.html页面

<script>
 document.domain = 'a.com';
</script>

这样俩个页面就可以通过js相互访问各种属性和对象了。

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,因为主域已经不相同了。

(五) HTML5的window.postMessage

window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。
window.postMessage允许两个窗口/帧之间跨域发送数据消息。从本质上讲,window.postMessage是一个跨域的无服务器垫片的Ajax。

用法:
otherWindow.postMessage(message, targetOrigin);

  • otherWindow: 对接收信息页面的window的引用。可以是页面中iframe的contentWindow属性;window.+open的返回值;通过name或下标从window.frames取到的值。
  • message: 所要发送的数据,string类型。
  • targetOrigin: 用于限制otherWindow,“*”表示不作限制

数据发送端
a.com/index.html中的代码:

<iframe id="ifr" src="b.com/index.html"></iframe>
<script type="text/javascript">
window.onload = function() {
 var ifr = document.getElementById('ifr');
 var targetOrigin = 'http://b.com'; // 设定接收端的域,*则为不限制
   
 ifr.contentWindow.postMessage('I was there!', targetOrigin);
};
</script>

数据接收端
b.com/index.html中的代码:

<script type="text/javascript">
 window.addEventListener('message', function(event){
 // 通过origin属性判断消息来源地址
 if (event.origin == 'http://a.com') {
 alert(event.data); // 弹出"I was there!"
 alert(event.source); // 对a.com、index.html中window对象的引用
   // 但由于同源策略,这里event.source不可以访问window对象
 }
 }, false);
</script>

以上就是js实现跨域的多种方法,希望对大家的学习有所帮助。

Javascript 相关文章推荐
jquery select(列表)的操作(取值/赋值)
Aug 06 Javascript
JavaScript iframe的相互操作浅析
Oct 14 Javascript
某人初学javascript的时候写的学习笔记
Dec 30 Javascript
js 利用image对象实现图片的预加载提高访问速度
Mar 29 Javascript
js跑步算法的实现代码
Dec 04 Javascript
javascript对中文按照拼音排序代码
Aug 20 Javascript
快速使用Bootstrap搭建传送带
May 06 Javascript
JavaScript学习小结之使用canvas画“哆啦A梦”时钟
Jul 24 Javascript
鼠标拖动改变DIV等网页元素的大小的实现方法
Jul 06 Javascript
通过一次报错详细谈谈Point事件
May 17 Javascript
js的对象与函数详解
Jan 21 Javascript
vue 实现路由跳转时更改页面title
Nov 05 Javascript
jquery.cookie.js用法实例详解
Dec 25 #Javascript
理解javascript中try...catch...finally
Dec 25 #Javascript
javascript实现简单加载随机色方块
Dec 25 #Javascript
学习JavaScript鼠标响应事件
Dec 25 #Javascript
理解javascript中DOM事件
Dec 25 #Javascript
理解JavaScript中worker事件api
Dec 25 #Javascript
基于jquery实现省市区三级联动效果
Dec 25 #Javascript
You might like
Terran魔法科技
2020/03/14 星际争霸
PHP下打开phpMyAdmin出现403错误的问题解决方法
2013/05/23 PHP
codeigniter中测试通过的分页类示例
2014/04/17 PHP
PHP中使用Imagick读取pdf并生成png缩略图实例
2015/01/21 PHP
详解在PHP的Yii框架中使用行为Behaviors的方法
2016/03/18 PHP
浅谈PHP中类和对象的相关函数
2017/04/26 PHP
thinkPHP5框架auth权限控制类与用法示例
2018/06/12 PHP
详解json在php中的应用
2018/09/30 PHP
jquery last-child 列表最后一项的样式
2010/01/22 Javascript
Javascript创建Silverlight Plugin以及自定义nonSilverlight和lowSilverlight样式
2010/06/28 Javascript
Javascript学习笔记 delete运算符
2011/09/13 Javascript
js中的时间转换—毫秒转换成日期时间的示例代码
2014/01/26 Javascript
js检测输入内容全为空格的方法
2014/05/03 Javascript
JavaScript验证图片类型(扩展名)的函数分享
2014/05/05 Javascript
js实现iframe跨页面调用函数的方法
2014/12/13 Javascript
浅谈Jquery核心函数
2015/06/18 Javascript
jQuery热气球动画半透明背景的后台登录界面代码分享
2015/08/28 Javascript
vue cli3.0打包上线静态资源找不到路径的解决操作
2020/08/03 Javascript
JavaScript 获取滚动条位置并将页面滑动到锚点
2021/02/08 Javascript
Python之Scrapy爬虫框架安装及使用详解
2017/11/16 Python
Python处理命令行参数模块optpars用法实例分析
2018/05/31 Python
利用python计算时间差(返回天数)
2019/09/07 Python
用python画一只可爱的皮卡丘实例
2019/11/21 Python
Python基于模块Paramiko实现SSHv2协议
2020/04/28 Python
Keras 中Leaky ReLU等高级激活函数的用法
2020/07/05 Python
html5调用摄像头功能的实现代码
2018/05/07 HTML / CSS
德国箱包网上商店:koffer24.de
2016/07/27 全球购物
美国在线艺术商店:HandmadePiece
2020/11/06 全球购物
师范生自荐信
2013/10/27 职场文书
银行实习生的自我评价
2014/01/13 职场文书
护士自我评价范文
2014/01/25 职场文书
室内趣味活动方案
2014/08/24 职场文书
领导班子四风对照检查材料范文
2014/09/27 职场文书
技术股东合作协议书
2014/12/02 职场文书
狮子林导游词
2015/02/03 职场文书
迎国庆主题班会
2015/08/17 职场文书