JS中的八种常用的跨域方式及其具体示例的总结

  这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据。
  跨域问题是由于javascript语言安全限制中的同源策略造成的。
  简单来说,同源策略是指一段脚本只能读取来自同一来源的窗口和文档的属性,这里的同一来源指的是域名、协议和端口号的组合只要协议、域名、端口有任何一个不同,都被当作是不同的域。

下表给出了相对http:// www.a.com/dir/a.html同源检测的结果:

特别注意两点:

1、如果是协议和端口造成的跨域问题“前台”是无能为力的;
2、在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。

URL的首部:指window.location.protocol +window.location.host,也可以理解为“Domains(域名), protocols(协议) and ports(端口) must match”。

要解决跨域的问题,我们可以使用以下几种方法:

方法一、通过jsonp跨域

JSONP包含两部分:回调函数和数据。
回调函数:当响应到来时要放在当前页面被调用的函数。
数据:就是传入回调函数中的json数据,也就是回调函数的参数了。

/*handleResonse({"data": "zhe"})*/
//原理如下:
//当我们通过script标签请求时
//后台就会根据相应的参数(json,handleResponse)
//来生成相应的json数据(handleResponse({"data": "zhe"}))
//最后这个返回的json数据(代码)就会被放在当前js文件中被执行
//至此跨域通信完成
//1、使用JS动态生成script标签,进行跨域操作
function handleResponse(response){console.log('The responsed data is: '+response.data);//处理获得的Json数据
}
var script = document.createElement('script');
script.src = 'http://www.example.com/data/?callback=handleResponse';
document.body.insertBefore(script, document.body.firstChild);
--------------------------
//2、手动生成script标签
function handleResponse(response){console.log('The responsed data is: '+response.data);//处理获得的Json数据
}
<script src="http://www.example.com/data/?callback=handleResponse"></script>
--------------------------
//3、使用jQuery进行jsonp操作
//jquery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁
//$.getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用jsonp的回调函数。
<script>$.getJson('http://www.example.com/data/?callback=?',function(jsondata){//处理获得的Json数据
});
</script>

jsonp虽然很简单,但是有如下缺点

1)安全问题(请求代码中可能存在安全隐患)

2)要确定jsonp请求是否失败并不容易

方法二、通过document.domain+iframe来跨子域(只有在主域相同的时候才能使用该方法) 

浏览器同源策略限制:

  1. 不能通过ajax的方法去请求不同源中的文档。
  2. 浏览器中不同域的框架之间是不能进行js的交互操作的。

  所以,在不同的框架之间(父子或同辈),是能够获取到彼此的window对象的,但不能使用获取到的window对象的属性和方法(html5中的postMessage方法是一个例外),总之,你可以当做是只能获取到一个几乎无用的window对象
  例如,在一个页面 http:// www.example.com/a.html 中,有一个iframe框架它的src是http:// example.com/b.html, 很显然,这个页面与它里面的iframe框架是不同域的,所以我们是无法通过在页面中书写js代码来获取iframe中的东西的:

//  http://www.example.com/a.html 页面中
<script>function onLoad(){var iframe = document.getElementById('iframe');var win = iframe.contentWindow;//这里能够获取到iframe中的window对象,但是window对象的属性和方法几乎不可用。var doc = win.document;//这里获取不到iframe中的document对象var name = win.name;//这里获取不到window对象的name属性······
}
<iframe id = "iframe" src ="http:// example.com/b.html" onload = "onLoad()"></iframe>

所以我们就要用到document.domain

1) 在页面http:// www.a.com/dir/a.html中设置document.domain:

<iframe src = "http://script.a.com/dir/b.html" id="iframe" onload = "loLoad()"></iframe>
<script>document.domain = "a.com";//设置成主域
function test(){var iframe = document.getElementById("iframe");var win = iframe.contentWindow;//在这里就可以操作b.html
}</script>

2) 在http:// script.a.com/dir/b.html也需要显示的设置document.domain

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

注意,document.domain的设置是有限制的:

  我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。
  例如:a.b.c.com 中某个文档的document.domain 可以设成a.b.c.com、b.c.com 、c.com中的任意一个

方法三、使用window.name+iframe来进行跨域

   window的name属性特征:name 值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB),即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面window.name都有读写的权限。

  正是由于window的name属性的特征,所以可以使用window.name来进行跨域。
  举例:
  1>在一个a.html页面中,有如下代码:

<script>window.name = "哈哈,我是页面a设置的值哟!";//设置window.name的值setTimeout(function(){window.location = 'b.html';},3000);//3秒后把一个新页面载入当前window</script>

  2>再在b.html中读取window.name的值:

<script>alert(window.name);//读取window.name的值</script>

  3>a.html载入3秒后,跳转到b.html页面中,结果为:
  

注意:
1.window.name的值只能是字符串的形式,这个字符串的大小最大能允许2M左右甚至更大的一个容量,具体取决于不同的浏览器。

接下来使用window.name进行跨域举例

  比如:有一个example.com/a.html页面,需要通过a.html页面里的js来获取另一个位于不同域上的页面cnblogs.com/data.html里的数据。
  1)创建cnblogs.com/data.html代码:

<script>window.name = "我是data.html的数据,所有可以转化为字符串来传递的数据都可以在这里使用,比如这里可以传递Json数据";</script>

  2)创建example.com/a.html的代码:
  想要即使a.html页面不跳转也能得到data.html里的数据。在a.html页面中使用一个隐藏的iframe来充当一个中间人角色,由iframe去获取data.html的数据,然后a.html再去得到iframe获取到的数据。

<script>function getData(){//iframe载入data.html页面会执行此函数var ifr = document.getElementById("iframe");ifr.onload = function(){//这个时候iframe和a.html已经处于同一源,可以互相访问var data = ifr.contentWindow.name;
//获取iframe中的window.name,也就是data.html中给它设置的数据alert(data);}ifr.src = 'b.html';//这里的b.html为随便一个页面,只要与a.html同源就行,目的是让a.html能够访问到iframe中的东西,否则访问不到}</script>
<iframe id = "iframe" src = "cnblogs.com/data.html" style = "display:none" onload = "getData()"></iframe>

方法四、使用window.postMessage方法来跨域(不常用)

  window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源(可实现跨域),目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。
  message:为要发送的消息,类型只能为字符串;
  targetOrigin:用来限定接收消息的那个window对象所在的域,如果不想限定域,可以使用通配符 “*”。

  1)创建www.test.com/a.html页面代码:

<script>function onLoad(){var iframe = document.getElementById("iframe");var win = iframe.contentWindow;win.postMessage('哈哈,我是来自页面a.html的信息哟!','*');//向不同域的www.script.com/b.html发送消息
}</script>
<iframe id="iframe" src="www.script.com/b.html" onload="onLoad()"></iframe>

  2)创建www.script.com/b.html页面代码:

<script>window.onmessage = function(e){//注册message时间来接收消息e = e || event;            //获取时间对象alert(e.data);             //通过data属性来得到传送的消息
}</script>

优点:使用postMessage来跨域传送数据还是比较直观和方便的;
缺点: IE6、IE7不支持,所以用不用还得根据实际需要来决定。

方法五、使用跨域资源共享(CORS)来跨域

  CORS:一种跨域访问的机制,可以让AJAX实现跨域访问;CORS允许一个域上的网络应用向另一个域提交跨域AJAX请求。
  服务器设置Access-Control-Allow-Origin HTTP响应头之后,浏览器将会允许跨域请求.
  就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。

  1) IE中对CORS的实现是通过xdr

var xdr = new XDomainRequest();
xdr.onload = function(){console.log(xdr.responseText);
}
xdr.open('get', 'http://www.test.com');
......
xdr.send(null);

  2) 其它浏览器中的实现就在xhr中

var xhr =  new XMLHttpRequest();
xhr.onreadystatechange = function () {if(xhr.readyState === 4 && xhr.status === 200){console.log(xhr.responseText);} }
}
xhr.open('get', 'http://www.test.com');
......
xhr.send(null);

  3) 实现跨浏览器的CORS

function createCORS(method, url){var xhr = new XMLHttpRequest();if('withCredentials' in xhr){xhr.open(method, url, true);}else if(typeof XDomainRequest != 'undefined'){var xhr = new XDomainRequest();xhr.open(method, url);}else{xhr = null;}return xhr;
}
var request = createCORS('get', 'http://www.test.com');
if(request){request.onload = function(){......};request.send();
}

方法六、使用location.hash+iframe来跨域(不常用)

  假设域名test.com下的文件a.html要和csdnblogs.com域名下的b.html传递信息。
  1) 创建test.com下的a.html页面, 同时在a.html上加一个定时器,隔一段时间来判断location.hash的值有没有变化,一旦有变化则获取获取hash值,代码如下:

<script>function startRequest(){var ifr = document.createElement('iframe');//创建一个隐藏的iframeifr.style.display = 'none';ifr.src = 'http://www.csdnblogs.com/b.html#paramdo';//传递的location.hashdocument.body.appendChild(ifr);
}
function checkHash() {try {var data = location.hash ? location.hash.substring(1):'';if (console.log) {console.log('Now the data is ' + data);}} catch (e) {};
}
setInterval(checkHash, 5000);
window.onload = startRequest;</script>

  2) b.html响应请求后再将通过修改a.html的hash值来传递数据,代码如下:

<script>function checkHash() {var data = '';//模拟一个简单的参数处理操作switch (location.hash) {case '#paramdo':data = 'somedata';break;case '#paramset'://do something……break;default:break;}data && callBack('#' + data);
}
function callBack(hash) {// ie、chrome的安全机制无法修改parent.location.hash//所以要利用一个中间的www.csdnblogs.com域下的代理iframevar proxy = document.createElement('iframe');proxy.style.display = 'none';proxy.src = 'http://www.csdnblogs.com/c.html' + hash; // 注意该文件在"www.csdnblogs.com"域下document.body.appendChild(proxy);
}
window.onload = checkHash;</script>

  3) test.com域下的c.html代码:

<script>
//因为parent.parent和自身属于同一个域,所以可以改变其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);
</script>

方法七、使用Web sockets来跨域

web sockets: 是一种浏览器的API,它的目标是在一个单独的持久连接上提供全双工、双向通信。(同源策略对web sockets不适用)

web sockets原理:在JS创建了web socket之后,会有一个HTTP请求发送到浏览器以发起连接。取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为web sockt协议。

<script>var socket = new WebSockt('ws://www.test.com');
//http->ws; https->wss
socket.send('hello WebSockt');
socket.onmessage = function(event){var data = event.data;
}

方法八、使用flash URLLoader来跨域

  flash有自己的一套安全策略,服务器可以通过crossdomain.xml文件来声明能被哪些域的SWF文件访问,SWF也可以通过API来确定自身能被哪些域的SWF加载。
  例如:当跨域访问资源时,例如从域baidu.com请求域google.com上的数据,我们可以借助flash来发送HTTP请求。  

跨域实现方式:
 1.首先,修改域google.com上的crossdomain.xml(一般存放在根目录,如果没有需要手动创建) ,把baidu.com加入到白名单。
 2. 其次,通过Flash URLLoader发送HTTP请求
 3. 最后,通过Flash API把响应结果传递给JavaScript。

  Flash URLLoader是一种很普遍的跨域解决方案,不过需要支持iOS的话,这个方案就不可行了。
  
  以上八种方法,可以根据项目的实际情况来进行选择应用,个人认为window.name的方法既不复杂,也能兼容到几乎所有浏览器,这真是极好的一种跨域方法。

转载自: https://blog.csdn.net/wangchengiii/article/details/78081032

js如何实现跨域操作?(转)相关推荐

  1. Nginx允许跨域和禁止跨域操作

    Nginx默认是禁止跨域操作,可能说到跨域好多伙伴会有点迷糊,什么叫跨域?为什么不能跨域呢?  看下面小编的详解. url 说明 是否跨域 http://www.cnblogs.com/a.js ht ...

  2. 原创:通过jQuery进行跨域操作

    之前尝试过用aJax做的一些跨域请求,一般都是在本地可以跨域,但放到服务器上就不行了. 现在找到了一种更好的方法:.NET+$.getJSON,代码非常简洁,可以兼容各种主流浏览器,不会弹出安全提示对 ...

  3. ASP.NET MVC (四、ASP.NET Web API应用程序与跨域操作)

    目录 前言: 1.创建MVC项目 2.修改返回格式 3.创建[Web API]控制器 4.创建[HttpGet]访问接口 5.创建[HttpPost]访问接口 6.测试接口: 6.1.执行:点击[调试 ...

  4. 使用iframe+postMessage跨域操作和通信

    使用iframe+postMessage跨域操作和通信 场景 1. http://XXX/a.html(自己的)页面要操作http://YYY/b.html(其他域名的) 2. 看了网上很多都是同域名 ...

  5. node ,express框架后台设置跨域操作,路由中间件

    express项目入口文件下app.js 设置跨域操作 app.all('*', function(req, res, next) { res.header("Access-Control- ...

  6. 原生js的JSONP跨域请求

    但到目前为止最被推崇或者说首选的方案还是用JSON来传数据,靠JSONP来跨域. JSONP跨域GET请求是常用的解决方案. 在进行一些比较深入的前端操作时,不可避免的要进行跨域操作,但是 基于安全的 ...

  7. JS中的跨域问题及解决办法汇总

    一.什么是跨域? 在了解跨域之前,首先要知道什么是同源策略(same-origin policy).简单来讲同源策略就是浏览器为了保证用户信息的安全,防止恶意的网站窃取数据,禁止不同域之间的JS进行交 ...

  8. js解决iframe跨域问题

    js解决iframe跨域问题 参考文章: (1)js解决iframe跨域问题 (2)https://www.cnblogs.com/qinxuhui/p/12154995.html 备忘一下.

  9. [转] js前端解决跨域问题的8种方案(最新最全)

    [转] js前端解决跨域问题的8种方案(最新最全) 参考文章: (1)[转] js前端解决跨域问题的8种方案(最新最全) (2)https://www.cnblogs.com/chris-oil/p/ ...

最新文章

  1. 操作系统知识点:全面
  2. 希尔排序——算法系列
  3. R读取json文件并转化为dataframe
  4. Javascript+xmlhttp调用Webservice
  5. Yii AR Model 查询
  6. java动态执行逻辑_动态执行代码逻辑
  7. 【深度学习】解决物体检测中的小目标问题
  8. 小米手机硬改技术_小米11手机爆料:首发骁龙875 或采用屏下摄像头技术
  9. EXE.DLL文件图标导出器[免费下载]
  10. docker安装xxl-job-admin步骤
  11. js - 预加载+监听图片资源加载制作进度条
  12. Julia的Dates库是重要和必要的补充!
  13. C语言程序设计课题分析,C语言程序设计综合实践性教学课题报告.doc
  14. Android-Studio 缓存文件夹配置
  15. 魔乐MLDN李兴华主讲Oracle视频教程
  16. 一种基于深度神经网络的临床记录ICD自动编码方法
  17. vue 登录页背景-粒子特效(Vue-Particles)
  18. R数据分析:样本量计算的底层逻辑与实操,pwr包
  19. vue 引入第三方文件(高拍仪),传值及接口调用。
  20. python实例013--定义一个矩形类

热门文章

  1. android x8,3英寸高性价比Android手机 索爱X8评测
  2. java-php-python-springboot智能物流运输管理系统登录计算机毕业设计
  3. 2020-02-28-E-prime主要常见问题及matlab、python打marker方式
  4. 发展认知科学EEG研究: 新视角与挑战
  5. 【华为OD统一考试B卷 | 100分】最长公共后缀(C++ Java JavaScript Python)
  6. 阿里开源流控框架 - Sentinel入门介绍
  7. ERP系统方案的实施步骤
  8. vmware下windows磁盘分区扩容
  9. 数字经济数据2009-2019年、数字经济发展指标体系和测算2011-2020年、地级市数字经济数据2011-2019年、数字经济发展指数2011-2020年
  10. 基于FPGA的数码管显示出租车计费器