这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据。只要协议、域名、端口有任何一个不同,都被当作是不同的域。

特别注意两点:

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

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

方法一、通过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');
//创建一个隐藏的iframe
ifr.style.display = 'none';
ifr.src = 'http://www.csdnblogs.com/b.html#paramdo';
//传递的location.hash
document.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域下的代理iframe
var 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处理的8种跨域方法的更多相关文章

  1. 同源策略(same-origin policy)及三种跨域方法

    同源策略(same-origin policy)及三种跨域方法 1.同源策略 含义: 同源是指文档的来源相同,主要包括三个方面 协议 主机 载入文档的URL端口 所以同源策略就是指脚本只能读取和所属文 ...

  2. js中几种实用的跨域方法原理详解(转)

    今天研究js跨域问题的时候发现一篇好博,非常详细地讲解了js几种跨域方法的原理,特分享一下. 原博地址:http://www.cnblogs.com/2050/p/3191744.html 下面正文开 ...

  3. js中几种实用的跨域方法原理详解

    这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...

  4. [转]js中几种实用的跨域方法原理详解

    转自:js中几种实用的跨域方法原理详解 - 无双 - 博客园 // // 这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同 ...

  5. js中几种实用的跨域方法原理详解【转】

    源地址:http://www.cnblogs.com/2050/p/3191744.html 这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通 ...

  6. 【转】js中几种实用的跨域方法原理详解

    这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...

  7. 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之十二 || 三种跨域方式比较,DTOs(数据传输对象)初探

    更新反馈 1.博友@落幕残情童鞋说到了,Nginx反向代理实现跨域,因为我目前还没有使用到,给忽略了,这次记录下,为下次补充.此坑已填 2.提示:跨域的姊妹篇——<三十三║ ⅖ 种方法实现完美跨 ...

  8. 前端Js跨域方法汇总—剪不断,理还乱,是跨域

    1.通过jsonp跨域2.通过修改document.domain来跨子域(iframe)3.隐藏的iframe+window.name跨域4.iframe+跨文档消息传递(XDM)5.跨域资源共享 C ...

  9. 「JavaScript」JS四种跨域方式详解

    原文地址https://segmentfault.com/a/1190000003642057 超详细并且带 Demo 的 JavaScript 跨域指南来了! 本文基于你了解 JavaScript ...

随机推荐

  1. Java Web之分页的实现(通用)

    一.用到的工具类的封装 为了实现代码的重用性,我们将经常用到的代码封装到工具类中,以便在任何地方都可以调用 1.获取路径工具 在jsp页面中,我们经常会向Servlet发送请求,并通过反射,实现通过传 ...

  2. CF447B DZY Loves Strings 贪心

    DZY loves collecting special strings which only contain lowercase letters. For each lowercase letter ...

  3. 洛谷P2184 贪婪大陆

    题目背景 面对蚂蚁们的疯狂进攻,小FF的\(Tower\) \(defence\)宣告失败--人类被蚂蚁们逼到了\(Greed\) \(Island\)上的一个海湾.现在,小FF的后方是一望无际的大海 ...

  4. thinkphp5.1控制器初始化函数initialize与构造函数__construct区别

    构造函数中子类的构造方法会覆盖父类的构造方法,如果要继承父类的构造方法可以加入parent::__construct(); 例子: //另一种方法,使用构造函数初始化 public function ...

  5. UVa 10652(旋转、凸包、多边形面积)

    要点 凸包显然 长方形旋转较好的处理方式就是用中点的Vector加上旋转的Vector,然后每个点都扔到凸包里 多边形面积板子求凸包面积即可 #include <cstdio> #incl ...

  6. <select> js中 设置选重

    function ChangeSelect(n)      {          var selectnum=n;        var kk = document.getElementById(&q ...

  7. input累加赋值

    需求如下:第一个input添加字符到第二个input,第二个input需要累加. html: <tr> <td rowspan="2" class="D ...

  8. jmeter压测配置

    windows上面修改最大使用端口数和time_await等待时间 注册表需要添加两个配置,位置:HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ S ...

  9. ubuntu下编译安装mysql记录

         搞了整整一天,好不容易折腾完,在此记录下,下次就省事了.     去官网http://www.php.net/downloads.php下载所需要的php版本,这里我选择5.6.22.    ...

  10. [LeetCode]3. Longest Substring Without Repeating Characters无重复字符的最长子串

    Given a string, find the length of the longest substring without repeating characters. Example 1: In ...