前端跨域的那些事

这一节,我们来讲一讲,前端跨域的那些事,主要分成这样的几部分来讲解,

一、为什么要跨域?

二、常见的几种跨域与使用场景

  2.1 JSONP跨域

  2.2 iframe跨域

  2.3 window.name 跨域

  2.4 document.domain 跨域

  2.5 cookie跨域

  2.6 postMessage跨域

三、总结

一、为什么要跨域

 跨域,通常情况下是说在两个不通过的域名下面无法进行正常的通信,或者说是无法获取其他域名下面的数据,这个主要的原因是,浏览器出于安全问题的考虑,采用了同源策略,通过浏览器对JS的限制,防止恶意用户获取非法的数据。比如这样的一个场景,恶意用户仿造一个银行的官网,在用户输入框中嵌套了银行的页面,如果是没有同源策略的限制,那么恶意用户则可以通过这样的一种方法来获取银行用户的卡号和登录密码,这样对于浏览器来说是没有安全性可言的。同时也可以有效的规避了大部分的XSS攻击(XSS攻击原理:通过向用户界面中注入script脚本,然后在脚本中获取用户的token等身份信息,然后将身份信息发送到恶意用户指定的地方,在正常用户还没有推出的时候,也就是token等身份信息还有效的时候,通过这些信息强制登录,将正常用户挤下系统。)

 

二、常见的几种跨域与使用场景

前端的跨域主要有:JSONP跨域、iframe跨域、window.name 跨域、document.domain 跨域、cookie跨域、postMessage跨域  后端的跨域:http配置

这里我们就主要说明一下前端的跨域,后端的跨域方法不做说明:

跨域方式特点局限
JSONP跨域1、JSONP跨域不是一种前端技术,而是程序猿创造的一种跨域方法
2、JSONP跨域,是一种简单的跨域方法,兼容性比较好
 
iframe 跨域1、操作简便 2、兼容性好单纯的使用iframe跨域无法获取其他域名下的数据
window.name 跨域1、必须与iframe配合使用 2、可以获取其他域名下的数据 
document.domain 跨域1、必须保证两个要跨域的对象是有一个关联域名  1、只针对两个跨域对象是关联域名   2、如果一个域名被攻击,那么另外一个域名也有安全问题
cookie跨域1、这种方法跨域的兼容性好,由于需要一些额外的设置,所以删除cookie的时候比较繁琐必须保证两个域名为关联域名
postMessage跨域1、这种方法可以直接实现将数据从A站点传输到B站点,而且解除了cookie的限制和JSONP无法获取要传入的站点的信息这个为HTML5新增加的特性,浏览器的兼容性不是很好,低版本的浏览器不支持,具体可以见:CANIUSE网站

2.1 JSONP跨域

JSONP跨域主要的依据是利用一些HTML标签的“漏洞”,然后通过跨域的方式去调用这个在别的域名下面的脚本文件,JSONP跨域有script跨域

我们先来一个简单的例子,我们先下载一个phpStudy,然后配置两个本地服务器,分别为:www.test1.com、www.test2.com

在www.test1.com域名下面我们添加一个test.js文件,内容如下:  

alert("test!");

 

然后在www.test2.com域名下面我们添加一个HTML文件,如下所示:

复制代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Document</title>
</head>
<body><script src="http://www.test1.com/test.js" />
</body>
</html>
复制代码

这个相信大多数人都是见过的,可能你会说这个不就是简单的script脚本的引入吗?对的,就是因为script支持跨域,这个也就是我们常见的CDN。但是上面的例子只能说是一个简单的JSONP跨域的应用而已,跨域的目的是要实现数据的传输。我们可以按照这个思路这样去改写:

首先我们可以在一个域名下面书写一个方法,然后通过在外部加载一个脚本来调用这个方法,向这个方法中去传值,这样就可以实现把外部的数据传到当前的域名的下面,从而实现了跨域。

我们在test.js文件下面定义一个

test("tthis is js load script");

 www.test2.com下面的HTML文件

复制代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Document</title>
</head>
<body><script type="text/javascript">var test=function(data){alert(data);}</script><script type="text/javascript" src="DEMO.js"></script>
</body>
</html>
复制代码

这个我们可以理解为是在一个HMTL文件中书写一个test方法,然后test方法允许调用的时候向里面传参,之后通过外部加载一个JS文件,JS文件实现的逻辑是调用这个方法,所以我们不能够把定义的test方法放在调用的DEMO.js的文件后面,因为如果我们这样做了的话,那么在调用外部的JS文件的时候,test方法没有加载进来所以我们便看不到效果所在,这个有兴趣的同学可以自己去试验一下,这里就不做试验了。

在实际的应用中,这样的例子是基本上不可能看到的,因为这样的参数传递太过于死板,应用性不强,我们在实际的应用中应该要达到的效果是可以根据我们的需求做出相应的响应,这样说吧,大家可能都知道或者调用过接口吧,接口其实我们可以理解为就是JSONP的一种应用,接下来我们就来试验一下:

说了这么多,大家应该还是对具体怎样使用有点云里雾里的吧,现在我们就基于JSONP的思想来制作一个简易的音乐专辑查询器

首先我们应该要找到一个可以查询专辑的公共接口

http://cgi.music.soso.com/fcgi-bin/fcg_search_xmldata.q?source=10&w=关键字&perpage=1&ie=utf-8

然后我们就编写如下的HTML代码:

复制代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>JSONP2</title>
</head>
<body><input type="text" id="song" name=""><input type="button" id="song_search" value="歌曲搜索" name=""><br /><div style="width:200px;height:200px;background:pink" id="song_list"></div><script type="text/javascript" src="http://code.jquery.com/jquery-2.1.1.min.js"></script><script type="text/javascript">var searchJsonCallback=function(data){//遍历查询结果var alb_html='';for(var i in data.list){alb_html+='<span>专辑:</span><div style="color:black">'+data.list[0].albumname+'</div>';}$("#song_list").html(alb_html);}$("#song_search").on("click",function(){var keyword=$("#song").val();if(keyword==undefined||keyword==""){alert("歌曲搜索不能为空");return false;}else{var url = "http://cgi.music.soso.com/fcgi-bin/fcg_search_xmldata.q?source=10&w="+keyword+"&perpage=1&ie=utf-8";// 创建script标签,设置其属性var script = document.createElement('script');script.setAttribute('src', url);// 把script标签加入head,此时调用开始document.getElementsByTagName('head')[0].appendChild(script); }})    </script> 
</body>
</html>
复制代码

 

效果如下:

 

这个就是JSOP在实际中的应用,如果直接用ajax来实现的话,原理也是一样,只不过要把script标签换成ajax调用而已。

如果你要全部使用jquery来实现的话,那么只需要把ajax中的dataType类型换成jsonp即可(通过上面的例子我们知道script加载实际上也是一个get请求,这个可以在network中验证),这个有兴趣的同学可以查一查资料。

 

2.2 iframe跨域

iframe跨域的原理跟script跨域一样,但是我们要注意的是标签自身功能的差异性,具体差异如下:

1、script单纯就是引入的作用,但是iframe标签还有一个作用是显示的作用可以把远程加载的HTML代码显示出来,也就是script无法引入HTML代码文件

2、script标签只能够从远程获取数据,无法操作远程文件执行。但是iframe可以这样

上面的第二点说起来有点难理解,我们就通过一个例子来说明一下:

假设有这样的一个需求我们需要在www.jsonp1.com下面调用一个方法来清除josnp2.com下面的本地存储,

首先我们在jsonp1.com下面的index.html中加入script标签去调用jsonp2.com下面的js文件

具体如下:

window.localStorage.clear();
alert(1);

 

结果是:

我们可以看到内容为1的弹窗,但是在jsonp2的本地存储就没有被清除,所以我们可以得出结论,script标签的跨域适用于从远程获取数据,不适用对远程的操作。

这个需求我们可以使用iframe标签来实现:

jsonp1.com中的HTML文件如下:

复制代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>jsonp1</title>
</head>
<body><iframe src="http://www.jsonp2.com/demo.html"></iframe>
</body>
</html>
复制代码

 

jsonp2下面的demo.html:

复制代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Document</title>
</head>
<body><script type="text/javascript">window.localStorage.clear();alert("清除成功");</script>
</body>
</html>
复制代码

 

这样我们就实现了通过在JSONP1中调用JSONP2中的文件来清除JSONP2中的本地存储

但是大家想一想,我们除了使用这种方法来控制远程操作之外,我们还可以像script跨域一样来获取本地存储的数据吗?

答案是理论上是不可以实现的(本例子为博主的思路的构思,没有具体实践过,如有错误望各位指出),如图所示:

 首先我们就在jsonp1.com网站下面的index.html文件下面通过iframe插入jsonp2.com/index.html,这样我们就使用了iframe跨域,但是由于同源策略的限制,所以无法将jsonp2.com/index.html的值回传给jsonp1.com/index.html,所以这个时候在jsonp2.com/index.html是可以获取到站点的本地存储的,我们就可以像上面音乐接口去使用,把本地储存中的数值,传递过去,但是这个时候jsonp1.com/index.html文件是无法直接获取接口中返回的东西的,也无法通过jsonp2.com/index.html回调,所以这种方法是不可行的

但是我们就真的无法实现这样一个获取远程的站点的本地存储的功能吗?不是的这个时候利用window.name方法结合iframe来实现跨域

 

2.3 window.name 跨域

www.jsonp1.com下面的index.html代码:

复制代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head><title>跨域获取数据</title><script type="text/javascript">function domainData(url, fn){var isFirst = true;var iframe = document.createElement('iframe');iframe.style.width=0;iframe.style.height=0;iframe.style.display = 'none';var loadfn = function(){if(isFirst){iframe.contentWindow.location = 'http://www.jsonp1.com/proxy.html';isFirst = false;} else {//alert(1);//console.log(iframe.contentWindow.name);alert(iframe.contentWindow.name);iframe.contentWindow.document.write('');iframe.contentWindow.close();document.body.removeChild(iframe);iframe.src = '';iframe = null;}};iframe.src = url;if(iframe.attachEvent){iframe.attachEvent('onload', loadfn);} else {iframe.onload = loadfn;}document.body.appendChild(iframe);}</script>
</head>
<body></body><script type="text/javascript">domainData('http://www.jsonp2.com/demo.html', function(data){alert(data);});</script>
</html>
复制代码

www.jsonp2.com/demo.html代码如下:

复制代码
<script type="text/javascript">window.localStorage.setItem("test","123");var data=window.localStorage.getItem("test");window.localStorage.clear();window.name=data;</script>
复制代码

这样我们便可以实现在JSONP1的域名下面访问到JSONP2中的本地存储了,大家特别高兴有没有,反正这个需求当时做得时候也是挺困扰我的。

这里有一些注意事项要特别说明:

1、这个是在网上经过查找的代码,也可以说是一个比较标准的使用代码,大家在使用的时候可以参照业务需求进行该造。

2、在使用iframe这个标签之后要进行销毁,避免出现安全问题

3、window.name的使用必须建立在http协议的基础之上的,换句话来说就是不能直接打开网页一定要配置相应的本地域名(直接打开本地网页采用的是file协议)

 

2.4 document.domain 跨域

 这个的实现思路跟cookie跨域相似,都是在两个关联域名中设置document.domain值,然后让这两个值相等,这样就可以实现跨域操作,具体实现不给出,自行百度

 

2.5 cookie跨域

cookie跨域这个没有什么好说的,不清楚的同学请看我之前写过的一篇文章:cookie学习指南

 

2.6 postMessage跨域

 我们还是来实现一个上面的功能,在jsonp1域名下面获取jsonp2中localStorage的test字段的值,尝试着用postMessage来实现,具体的实现方式如下:

jsonp1.com下面的index.htm如下:

复制代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Document</title>
</head>
<body><div id="test"></div><textarea id="textarea"></textarea><iframe style="width:0px;height:0px" id="f" src="http://www.jsonp2.com/demo.html"></iframe><script type="text/javascript" src="http://cdn.bootcss.com/jquery/3.1.1/jquery.js"></script><script>var test1='';onmessage=function(e){e=e||event;// console.log(e);// console.log(e.data);test1=e.data;if(test1=="123"){alert("success!");}else{alert("error");}$("#test").html("<span style='color:red'>"+test1+"</span>");};</script>
</body>
</html>
复制代码

 jsonp2.com中的demo.html内容:

复制代码
<iframe id="f" src="http://www.jsonp1.com/index.html"></iframe>
<script>
var f=document.getElementById("f");
f.οnlοad=function(){window.localStorage.setItem("test","123");var value=window.localStorage.getItem("test");window.localStorage.clear();f.contentWindow.postMessage(value,"http://www.jsonp1.com");
}
</script>
复制代码

 这样就实现了一个从Jsonp2中获取本地存储的功能,但是在实践的过程中存在的一些问题需要引起我们的留意:

1、在两个需要跨域的文件都需要引入一个iframe来加载对方的路径

2、我们在使用的时候,是使用postMessage来发送信息给对方,然后我们是通过监控message事件来获取信息的

 

三、总结

这个篇文章主要总结了一些关于前端跨域方面的工作实践,与一些问题的探索,同时如果发现错误的话, 也希望各位能够指正。

分类: HTML5,深入学习JavaScript,项目经验,流行前端技术
标签: 教程, 笔记, JavaScript, HTML5, 前端, 工作总结

转载于:https://www.cnblogs.com/xiaocaiyuxiaoniao/p/8324943.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/267697.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VC++学习(15):多线程

1. 程序,进程,线程 A: 程序是计算机指令的集合,它以文件的形式存储在磁盘上,而进程通常被定义为一个正在运行的程序的实例,是一个程序在其自身的地址空间中的一次执行活动.一个程序可以对应多个进程. 进程是资源申请,高度和独立运行的单位,因此,它使用系统中的运行资源,而…

在linux中500g怎么分区,500G的硬盘,怎么分区比较合理?

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼个人电脑怎么分&#xff1f;希望大家给我规范一下另外&#xff0c;我的/dev/sda2用的是xfs&#xff0c;/dev/sda9用的是reiser4draplaterDrapl ~ $ sudo fdisk -l密码&#xff1a;Disk /dev/sda: 160.0 GB, 160041885696 bytes255 …

CSS宽高背景介绍

本萌新还未毕业&#xff0c;在一家外包公司干了一个月&#xff0c;因烦恼日常琐事任务&#xff0c;深感外包之坑&#xff0c;以及上班路途艰辛&#xff0c;特转战erp实施&#xff0c;继写日常随笔&#xff0c;望来日屌丝逆袭&#xff0c;走上人生巅峰。 若有错误&#xff0c;请…

linux交叉编译生成的是什么,静态链接util-linux – 交叉编译(生成动态链接文件)...

我一直试图交叉编译util-linux for arm但我一直以动态链接的可执行文件结束,我不知道为什么会这样.我的目标是静态的.我在使用类似步骤的不同工具之前进行了交叉编译,并且它一直有效,所以这次我不知道我做错了什么.我正在使用Ubuntu 16.04.以下是我正在运行的命令&#xff1a;e…

维护SAP帮助信息(WEB)

维护SAP帮助信息&#xff08;WEB&#xff09; 1、首先进入000 Client &#xff0c;然后scc4修改000的模式 2、spro 3、 4、 5、注意 服务器为&#xff1a;http://help.sap.com 路径为&#xff1a;saphelp_erp60_sp/helpdata 转载于:https://blog.51cto.com/anhwei/626111

读jQuery之十二(删除事件核心方法)

使用jQuery删除事件&#xff08;或称解除事件绑定&#xff09;有三个函数&#xff1a;unbind、die和undelegate。这三个方法都依赖于未公开的jQuery.event.remove&#xff08;后续使用remove简写&#xff09;。此为删除事件的核心方法。remove 所作的事情与上一篇提到的.add 刚…

像Excel一样使用python进行数据分析(1)

&#xff08;虽然是转载&#xff0c;但是是我每块都测试过得&#xff0c;容易出问题的地方我会添加一些自己的经验&#xff0c;仅供参考&#xff09; 像Excel一样使用python进行数据分析&#xff08;2&#xff09; 像Excel一样使用python进行数据分析&#xff08;3&#xff09;…

linux svn 自动部署,linux下svn安装和自动部署

liunx系统下安装svn并自动更新到项目中三部分&#xff1a;【1.安装 2.建立svn库 3.配置文件】html查看是否安装了svn 【svn –version】若是安装了svn能够先进行卸载 【sudo apt-get remove –purge subversion】接下来进行安装 【sudo apt-get install subversion】当安装成功…

css优先级

很经典的文章啊 [转]CSS的优先级特性Specificity 如果同个元素有两个或以上冲突的CSS规则&#xff0c;浏览器有一些基本的规则来决定哪一个非常特殊而胜出。它可能不像其它那么重要&#xff0c;大部分案例你不需要担心冲突&#xff0c;但大型而且复杂的CSS文件&#xff0c;或有…

linux编译准备,Linux 下编译指南

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼首先&#xff0c;我们需要获取最新的源码。使用如下命令即可&#xff1a;git clone -b master --depth1 https://github.com/CleverRaven/Cataclysm-DDA.git这条命令会只获取 master 分支下最新的代码。对于普通玩家来说这已经足够…

ServletConfig的详解

一、Servlet的作用 servlet是在servlet容器内运行的程序&#xff0c;有时需要访问容器外部或借助容器访问外部资源。所以可以通过web.xml文件中为某个servlet配置的名称和参数等信息传递给servlet。 这样做的好处是&#xff1a;如果将重要的信息、编码方式等配置信息放在web.xm…

You can't specify target table 'tablename' for update in FROM clause的解决方法

在执行下面的sql时报错 DELETE FROM temp WHERE id IN (SELECT a.id FROM t_user t JOIN temp a ON t.email a.email); 这种写法在sqlserver或者oracle中是支持的&#xff0c;但是mysql目前是不支持的&#xff0c;在mysql中不能同时查询一个表的数据再同时进行删除&#xff0…

linux缓存代码,Linux使用的缓存

Linux使用的缓存6.7.1 Linux使用的缓存不管在硬件设计还是软件设计中&#xff0c;高速缓存是获得高性能的常用手段。Linux 使用了多种和内存管理相关的高速缓存。1&#xff0e; 缓冲区高速缓存&#xff1a;缓冲区高速缓存中包含了由块设备使用的数据缓冲区。这些缓冲区中包含了…

Linux查看文件夹大小du

du命令参数详解见&#xff1a; http://baike.baidu.com/view/43913.htm 下面我们只对其做简单介绍&#xff1b; 查看linux文件目录的大小和文件夹包含的文件数 统计总数大小 du -sh filename&#xff08;其实我们经常用du -sh *&#xff0c;显示当前目录下所有的文件及其大小&a…

cursor: mutex S等待事件

cursor: mutex * events等待事件 cursor: mutex * events等待事件用于Cursor Parent 和 Cursor stats类型的操作&#xff1a; ‘Cursor: Mutex S’ &#xff0c; 某个进程以SHRD S mode申请一个Mutex&#xff0c; 而该Mutex要么被其他进程已EXCL X mode所持有&#xff0c;要么其…

flash和linux文件系统,面向大容量Flash的高效Linux文件系统改进和实现

摘要&#xff1a;文件系统是Linux操作系统的重要组成部分.而本文对于面向大容量Flash文件系统高效性的研究则主要侧重于对于嵌入式Linux操作系统文件系统的研究.由于嵌入式设备介质的特殊性,电源系统的不稳定性以及Flash容量的日益增长,大容量Flash设备文件系统高效性方面的问题…

Xshell配置ssh免密码登录-密钥公钥(Public key)

1 简介 ssh登录提供两种认证方式&#xff1a;口令(密码)认证方式和密钥认证方式。其中口令(密码)认证方式是我们最常用的一种&#xff0c;这里介绍密钥认证方式登录到linux/unix的方法。 使用密钥登录分为3步&#xff1a; 1、生成密钥&#xff08;公钥与私钥&#xff09;&#…

Linux面试题集锦,测测你的水平(答案)四

三&#xff0e;简答题&#xff1a;1&#xff0e;简述Linux文件系统通过i节点把文件的逻辑结构和物理结构转换的工作过程。参考答案&#xff1a;Linux通过i节点表将文件的逻辑结构和物理结构进行转换。i节点是一个64字节长的表&#xff0c;表中包含了文件的相关信息&#xff0c;…

linux vim ctags,Linux环境上代码阅读与编写的利器-vim+ctags+cscope

Linux环境下代码阅读与编写的利器----vimctagscscope所谓工欲善其事&#xff0c;必先利其器。从事Linux程序开发&#xff0c;特别是Linux驱动程序的开发&#xff0c;不管是通过windows下虚拟一个Linux,还是通过samba访问Linux都是很郁闷的事情。原因就是程序本身需要Linux的编译…

oracle vm中的xp添加共享文件夹

接着就可以在虚拟的电脑系统里面打开我们的共享文件夹&#xff0c;在桌面找到”网络邻居“&#xff0c;双击打开 我们需要通过”添加一个网络邻居“来加载我们刚才添加的”共享文件夹“&#xff0c;根据向导一步步执行 然后点击”浏览“ 展开前面的 ”“ visualBox shared fold…