复制代码,什么是跨域

数据交互与本地存储

2016/01/17 · HTML5, JavaScript · 1 评论 · 存储

原文出处: 涂根华   

一:Iframe父页面与子页面之间的调用

专业词语解释如下:

    Iframe:iframe元素是文档中的文档。

    window对象: 浏览器会在其打开一个HTML文档时创建一个对应的window对象。但是,如果一个文档定义了一个或者多个框架

(即:包含一个或者多个frame或者iframe标签),浏览器就会为原始文档创建一个window对象,再为每个iframe创建额外的window对象,这些额外的window对象是原始窗口的子窗口。

contentWindow: 是指指定的iframe或者iframe所在的window对象。

   1. 父页面与子页面之间的调用。

现在我们可以慢慢做demo来分别讲解下,假如有iframe父页面为 iframe1.html, 父页面上有2个子页面 分别为iframe2.html 和 iframe3.html。

父页面iframe1.html代码如下:

XHTML

<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="jquery1.7.js"></script> </head> <body> <iframe src="" id = "iframe3"></iframe> <iframe src="" id = "iframe2"></iframe> <div class="iframe1">父页面</div> <script> function test2() { console.log(1); } </script> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="jquery1.7.js"></script>
</head>
<body>
    <iframe src="http://localhost/iframe/iframe3.html" id = "iframe3"></iframe>
    <iframe src="http://localhost/iframe/iframe2.html" id = "iframe2"></iframe>
    <div class="iframe1">父页面</div>
   <script>
    function test2() {
        console.log(1);
    }
   </script>
</body>
</html>

子页面iframe2.html代码如下:

XHTML

<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="jquery1.7.js"></script> </head> <body> <div id="test">aaa</div> <div class="iframe2">子页面</div> <script> function b() { console.log("我是子页面"); } function iframe3Page() { console.log("iframe3页面调用iframe2页面"); } </script> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <script src="jquery1.7.js"></script>
</head>
<body>
    <div id="test">aaa</div>
    <div class="iframe2">子页面</div>
       <script>
           function b() {
           console.log("我是子页面");
       }
       function iframe3Page() {
           console.log("iframe3页面调用iframe2页面");
       }
      </script>
</body>
</html>

1.  子页面iframe2.html调用父页面 iframe1.html的元素如下代码:

    console.log($(‘.iframe1’,parent.document));

2.  子页面iframe2.html调用父页面iframe1.html的函数如下代码:

    parent.test2();

注意:父页面iframe1.html页面 中test2方法不能放在$(function(){}), 放在里面就调用不到。

3. 子页面iframe2.html调用自身的iframe(假如父页面有很多iframe,获取自身iframe不通过id或者name属性).

    1.首先我们可以在父页面上写一个函数 用来获取页面所有的iframe,之后进行遍历,进行判断当前的window对象是否相同。如下代码:

JavaScript

function getFrame(f){ var frames = document.getElementsByTagName("iframe"); for(i=0;i){ if(frames[i].contentWindow == f){ return(frames[i]) } } }

1
2
3
4
5
6
7
8
function getFrame(f){
    var frames = document.getElementsByTagName("iframe");
    for(i=0;i){
         if(frames[i].contentWindow == f){
              return(frames[i])
          }
      }
  }

    2. 在子页面iframe2.html中如下调用父页面的方法 getFrame.

JavaScript

/* 获取自身的iframe */ var aa = parent.getFrame(this); console.log(aa); $(aa).attr("flag",true);

1
2
3
4
/* 获取自身的iframe */
var aa = parent.getFrame(this);
console.log(aa);
$(aa).attr("flag",true);

给iframe2设置属性 flag: true, 如下截图:

图片 1

4. 父页面iframe1.html调用子页面 iframe2.html的元素及函数.

如下调用有误的:

console.log(document.getElementById(“iframe2”).contentWindow.b());

因为iframe2.html 有可能未加载完成,所以要等iframe2加载完成后再进行调用,

所以我们需要 iframe2.onload = function(){}; 这样再进行调用。为了兼容IE,我们可以如下封装一个方法:

JavaScript

function iframeIsLoad(iframe,callback){ if(iframe.attachEvent) { iframe.attachEvent('onload',function(){ callback & callback(); }); }else { iframe.onload = function(){ callback & callback(); } } } // 调用方式如下: // 父页面调用子页面iframe2的方法 var iframe2 = document.getElementById("iframe2"); iframeIsLoad(iframe2,function(){ iframe2.contentWindow.b(); // 打印出 我是子页面 // 父页面获取子页面iframe2的元素 var iframeDom = $(".iframe2",iframe2.contentWindow.document); console.log(iframeDom); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function iframeIsLoad(iframe,callback){
    if(iframe.attachEvent) {  
         iframe.attachEvent('onload',function(){
             callback & callback();
         });
 
    }else {
         iframe.onload = function(){
              callback & callback();
         }
    }
}
// 调用方式如下:
// 父页面调用子页面iframe2的方法
var iframe2 = document.getElementById("iframe2");
iframeIsLoad(iframe2,function(){
    iframe2.contentWindow.b(); // 打印出 我是子页面  
    // 父页面获取子页面iframe2的元素
    var iframeDom = $(".iframe2",iframe2.contentWindow.document);
    console.log(iframeDom);
 
});

二:理解JSONP跨域技术的基本原理

Javascript是一种在web开发中经常使用的前端动态脚本技术,在javascript中,有一个很重要的安全限制,被称为”same-Origin-Policy”同源策略,这一策略对于javascript代码能够访问的页面内容作了很重要的限制,即javascript只能访问与包含它的文档在同协议,同域名,同端口的脚本进行交互;

JSONP的基本原理是:利用在页面中创建节点的方法向不同域提交http请求的方法称为JSONP。

JSONP的具体实现方法如下:

首先我们为了演示跨域,我们在host文件夹下绑定如下2个域名如下:

   127.0.0.1  abc.example1.com

   127.0.0.1  def.example2.com

其中在abc.example1.com域名下有一个a.html页面;访问页面路径如下:

   

1. 我们在域名下abc.example1.com下的a.html页面引入一个域名为def.example2.com下的a.js文件;如下:

  然后在a.js代码变为如下:

JavaScript

   function jsonp(){         alert(1)    }   jsonp();

1
2
3
4
   function jsonp(){
        alert(1)
   }
  jsonp();

最后我们在域名下abc.example1.com下的a.html页面运行下可以看到弹出对话框 “1”;我们可以看到引入不同域名下的js文件也能跨域执行;

2. 如果我在域名为def.example2.com下的a.js文件能否调用a.html的方法名呢?我们继续来演示这个demo;我们在abc.example1.com下的a.html引入文件如下:

JavaScript

function jsonp(){     alert(1) }

1
2
3
4
5
function jsonp(){
 
    alert(1)
 
}

其中域名为def.example2.com下的a.js内容为:jsonp(); 我们继续来运行下页面,可以看到,还是可以弹出对话框 1;

3.  如果我在外面的调用方法能否传递一个参数呢?我们继续和第二点一样,只是方法里面多了一个参数传进去即可:如下代码:

def.example2.com下的a.js内容为:jsonp(“我是来测试的”);abc.example1.com下的a.html文件内容为:

JavaScript

 function jsonp(html){        alert(html)   }

1
2
3
 function jsonp(html){
       alert(html)
  }

我们运行下页面a.html,也可以看到弹出了对话框 “我是来测试的”文案;所以,我们就可以通过这种方法来给页面中传入外站的数据;可以实现JSONP的跨域数据;

理解JSONP执行过程如下:

    首先在客户端注册一个callback(比如jsonpcallback),然后把callback名字(比如叫jsonp123456)传给服务器端,服务器端得到callback名字后,需要用jsonp123456(),把将要输出的json内容包括起来,此时,服务器生成的json数据才能被客户端正确接收;然后以javascript语法的方式,生成一个function,function的名字就是传递回来的参数jsonp123456.然后就可以在客户端直接运行调用jsonp123456这个函数了;

演示代码如下:

在域名下abc.example1.com下的a.html页面代码如下:

动态创建script标签,给script动态设置src值为域名def.example2.com,这样就实现在不同的域名下了;

如下代码:

JavaScript

<script> function jsonp123456(data){ alert(data.name); // tugenhua alert(data.age); // 28 alert(data.single); // yes } var eleScript= document.createElement("script"); eleScript.type = "text/javascript"; eleScript.src = ""; document.getElementsByTagName("HEAD")[0].appendChild(eleScript); </script> //在def.example2.com域名下的a.js代码如下: jsonp123456({"name":'tugenhua','age':'28','single':'yes'});

1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
    function jsonp123456(data){
        alert(data.name); // tugenhua
        alert(data.age);  // 28
        alert(data.single); // yes
    }
    var eleScript= document.createElement("script");
    eleScript.type = "text/javascript";
    eleScript.src = "http://def.example2.com/iframe/a.js?jsonpcallback=jsonp123456";
    document.getElementsByTagName("HEAD")[0].appendChild(eleScript);
</script>
//在def.example2.com域名下的a.js代码如下:
jsonp123456({"name":'tugenhua','age':'28','single':'yes'});

分析: 在a.html下给服务器端发送请求,并且给服务器端传递参数 jsonpcallback=jsonp123456;服务器端拿到jsonpcallback这个参数后;需要用jsonp123456(),把将要输出的json内容包括起来,此时,服务器生成的json数据才能被客户端正确接收;然后以javascript语法的方式,生成一个function,function的名字就是传递回来的参数jsonp123456.然后就可以在客户端直接运行调用jsonp123456这个函数了;

如上演示的代码; 之后分别弹出data.name;data.age;及data.single;

JSONP的优点:

它不像XMLHttpRequest对象实现ajax请求受到同源策略的限制,它在所有的浏览器都支持,

比如古老的IE6也支持,并且在请求完成后可以通过callback的方式传回结果;

JSONP的缺点:

1. 只支持get请求,不支持post请求,它只支持http跨域的请求情况,

不能解决不同域的两个页面之间如何进行javascript调用的问题; 

  1. 由于它是get请求,传递的参数都拼在url后面,因此数据安全性不高;

三:iframe之间通信问题

1. iframe通信 分为:同域通信 和 跨域通信。所谓同域通信是指   下的a.html页面嵌套 iframe 比如: 的B.html页面,这两个页面数据进行通信,比如我想在父页面A.html 调用子页面当中的函数 我们很容易想到或者google下 ;document.getElementById(‘iframeA’).contentWindow.b(); 这种方法,其中b 是子页面B.html中的一个函数。但是这样调用下有个问题我纠结了很久,就是既然在火狐下报这样的错误, 如下图所示:

图片 2

b不是个函数 但是我在子页面明明定义了这么一个函数,那么为什么会报这样的错误呢?经过仔细分析及google,发现有这么一个问题需要理解,当iframe没有加载完成后 我就去执行这个js会报这样的错误,所以就试着在火狐下 用iframe.onload 这个函数 进行测试,果然没有报错,是正确的 所以就确定是这个问题。所以就想写个兼容IE和火狐 google写个函数 来确定iframe已经加载完成!,其实给个回调函数来调用我们上面的方法。

综合上面的思路 A.html 就可以写个这样的代码:

JavaScript

<iframe src="" id="iframeA" name="iframeA"></iframe> <div id="topName">topNddddddddddddddddame</div> <script> function A(){ alert("A"); } var iframe = document.getElementById('iframeA'); iframeIsLoad(iframe,function(){ var obj = document.getElementById('iframeA').contentWindow; obj.b(); }); function iframeIsLoad(iframe,callback){ if(iframe.attachEvent) { iframe.attachEvent('onload',function(){ callback && callback(); }); }else { iframe.onload = function(){ callback && callback(); } } } </script> B.html 代码如下: var b = function(){ alert("B"); };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<iframe src="http://localhost/demo/iframe/iframeB.html" id="iframeA" name="iframeA"></iframe>
<div id="topName">topNddddddddddddddddame</div>
<script>
    function A(){
        alert("A");
    }
    var iframe = document.getElementById('iframeA');
    iframeIsLoad(iframe,function(){
        var obj = document.getElementById('iframeA').contentWindow;
        obj.b();
    });
     function iframeIsLoad(iframe,callback){
        if(iframe.attachEvent) {
            iframe.attachEvent('onload',function(){
                callback && callback();
            });
        }else {
            iframe.onload = function(){
                callback && callback();
            }
        }
     }
</script>
B.html 代码如下:
var b = function(){
    alert("B");
};

2.子页面调用父页面的函数很简单,只要这样搞下就ok了,window.parent.A();

3. 子页面取父页面元素的值: window.parent.document.getElementById(“topName”).innerHTML等方法。

二: iframe跨域通信。

iframe跨域访问一般分为2种情况,第一种是同主域,不同子域的跨域。 第二种是:不同主域跨域。

一、 是同主域下面,不同子域之间的跨域;可以通过document.domain 来设置相同的主域来解决。

假如现在我有个域 abc.example.com 下有个页面叫abc.html, 页面上嵌套了一个iframe 如下:

XHTML

<iframe src="" id="iframe2" style="display:none;"></iframe>,

1
<iframe src="http://def.example.com/demo/def.html"  id="iframe2" style="display:none;"></iframe>,

我想在abc域下的页面abc.html 访问 def域下的def.html  我们都知道由于安全性 游览器的同源策略的限制,js不能操作页面不同域下 不同协议下 不同端口的页面,所以就要解决跨域访问了,假如父页面abc.html 页面有个js函数:

 function test(){console.log(1);};

 我想在子页面调用这个函数 还是按照上面的同域方式调用 parent.test();这样,通过在火狐下看 已经跨域了 解决的办法是 在各个js函数顶部 加一句 document.domain = ‘example.com’,就可以解决了。

 abc.html代码如下:

XHTML

<iframe src="" id="iframe2" style="display:none;"></iframe> // 跨域 子页调用父页的 函数 (假设是下面test函数) document.domain = 'example.com'; function test(){console.log(1);};

1
2
3
4
<iframe src="http://def.example.com/demo/def.html"  id="iframe2" style="display:none;"></iframe>
  // 跨域 子页调用父页的 函数 (假设是下面test函数)
  document.domain = 'example.com';
  function test(){console.log(1);};

def.html代码如下:

JavaScript

/* * 子页调用父页的方法 */ document.domain = 'example.com'; //window.top.test(); window.parent.test();

1
2
3
4
5
6
/*
* 子页调用父页的方法
*/
document.domain = 'example.com';
//window.top.test();
window.parent.test();

还是这两个页面 我想父页调用子页 如下方法:

a.html代码如下:

JavaScript

/* * 跨域 父页想调用子页的的函数 */ document.domain = 'example.com'; var iframe = document.getElementById('iframe2'); iframeIsLoad(iframe,function(){ var obj = iframe.contentWindow; obj.child(); }); function iframeIsLoad(iframe,callback){ if(iframe.attachEvent) { iframe.attachEvent('onload',function(){ callback & callback(); }); }else { iframe.onload = function(){ callback & callback(); } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
* 跨域 父页想调用子页的的函数
*/
document.domain = 'example.com';
var iframe = document.getElementById('iframe2');
iframeIsLoad(iframe,function(){
    var obj = iframe.contentWindow;
         obj.child();
});
function iframeIsLoad(iframe,callback){
        if(iframe.attachEvent) {
            iframe.attachEvent('onload',function(){
                callback & callback();
            });
        }else {
            iframe.onload = function(){
                callback & callback();
            }
        }
}

假如现在def.html页面有个child函数 代码如下:

JavaScript

document.domain = 'example.com'; function child(){console.log('我是子页');}

1
2
document.domain = 'example.com';
function child(){console.log('我是子页');}

就可以跨域调用了 不管是子页面调用父页面 还是父页面调用子页面。一切ok!

三:是不同主域跨域;

虽然google有几种方法关于不同主域上的跨域问题 有通过location.hash方法或者window.name方法或者html5及flash等等,

但是我觉得下面iframe这种方法值得学习下,如下图所示:

图片 3

域a.com的页面request.html(即

思路:要实现a.com域下的request.html页面请求域b.com下的process.php,可以将请求参数通过url传给response.html,由response.html向process.php发起真正的ajax请求(response.html与process.php都属于域b.com),然后将返回的结果通过url传给proxy.html,最后由于proxy.html和request.html是在同个域下,所以可以在proxy.html利用window.top 将结果返回在request.html完成真正的跨域。

ok, 先看看页面结构

a.com域下有:

 request.html  proxy.html

1
2
 request.html
 proxy.html

b.com域下有:

response.html Process.php

1
2
3
response.html
 
Process.php

先来看看request.html页面如下:

XHTML

<!DOCTYPE HTML> <html> <head> <title> New Document </title> </head> <body> <p id="result">这里将会填上响应的结果</p> <a id="sendBtn" href="javascript:void(0)">点击,发送跨域请求</a> <iframe id="serverIf" style="display:none"></iframe> <script> document.getElementById('sendBtn').onclick = function() { var url = '', fn = 'GetPerson', //这是定义在response.html的方法 reqdata = '{"id" : 24}', //这是请求的参数 callback = "CallBack"; //这是请求全过程完成后执行的回调函数,执行最后的动作 CrossRequest(url, fn, reqdata, callback); //发送请求 } function CrossRequest(url,fn,reqdata,callback) { var server = document.getElementById('serverIf'); server.src = url + '?fn=' +encodeURIComponent(fn) + "&data=" +encodeURIComponent(reqdata) + "&callback="+encodeURIComponent(callback); } //回调函数 function CallBack(data) { var str = "My name is " + data.name + ". I am a " + data.sex + ". I am " + data.age + " years old."; document.getElementById("result").innerHTML = str; } </script> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!DOCTYPE HTML>
<html>
<head>
  <title> New Document </title>
</head>
<body>
    <p id="result">这里将会填上响应的结果</p>
    <a id="sendBtn" href="javascript:void(0)">点击,发送跨域请求</a>
    <iframe id="serverIf" style="display:none"></iframe>
 
    <script>
        document.getElementById('sendBtn').onclick = function() {
            var url = 'http://b.com/demo/ajax/ajaxproxy/reponse.html',
                fn = 'GetPerson',          //这是定义在response.html的方法
                reqdata = '{"id" : 24}',   //这是请求的参数
                callback = "CallBack";     //这是请求全过程完成后执行的回调函数,执行最后的动作
 
            CrossRequest(url, fn, reqdata, callback);  //发送请求
        }
 
        function CrossRequest(url,fn,reqdata,callback) {
            var server = document.getElementById('serverIf');
            server.src = url + '?fn=' +encodeURIComponent(fn) + "&data=" +encodeURIComponent(reqdata) + "&callback="+encodeURIComponent(callback);
        }
        //回调函数
        function CallBack(data) {
            var str = "My name is " + data.name + ". I am a " + data.sex + ". I am " + data.age + " years old.";
             document.getElementById("result").innerHTML = str;
        }
    </script>
</body>
</html>

这个页面其实就是要告诉response.html:我要让你执行你定义好的方法GetPerson,并且要用我给你的参数'{“id” : 24}’。

response.html纯粹是负责将CallBack这个方法名传递给下一位仁兄proxy.html,而proxy.html拿到了CallBack这个方法名就可以执行了,

因为proxy.html和request.html是同域的。

response.html代码如下:

XHTML

<!DOCTYPE HTML> <html> <head> <title> New Document </title> </head> <body> <iframe id="proxy"></iframe> <script> // 通用方法 ajax请求 function _request (reqdata,url,callback) { var xmlhttp; if(window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); }else { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange = function(){ if(xmlhttp.readyState == 4 && xmlhttp.status == 200) { var data = xmlhttp.responseText; callback(data); } } xmlhttp.open('POST',url); xmlhttp.setRequestHeader("Content-Type", "application/json; charset=utf-8"); xmlhttp.send(reqdata); } // 通用方法 获取url参数 function _getQuery(key) { var query = location.href.split('?')[1], value = decodeURIComponent(query.split(key + "=")[1].split("&")[0]); return value; } //向process.php发送ajax请求 function GetPerson(reqdata,callback) { var url = ''; var fn = function(data) { var proxy = document.getElementById('proxy'); proxy.src = "" + encodeURIComponent(data) + "&callback=" + encodeURIComponent(callback); }; _request(reqdata, url, fn); } (function(){ var fn = _getQuery('fn'), reqdata = _getQuery("data"), callback = _getQuery("callback"); eval(fn + "('" + reqdata +"', '" + callback + "')"); })(); </script> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<!DOCTYPE HTML>
<html>
<head>
  <title> New Document </title>
</head>
<body>
     <iframe id="proxy"></iframe>
    <script>
        // 通用方法 ajax请求
        function _request (reqdata,url,callback) {
            var xmlhttp;
            if(window.XMLHttpRequest) {
                xmlhttp = new XMLHttpRequest();
            }else {
                xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            }
 
            xmlhttp.onreadystatechange = function(){
                if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                    var data = xmlhttp.responseText;
                    callback(data);
                }
            }
            xmlhttp.open('POST',url);
            xmlhttp.setRequestHeader("Content-Type", "application/json; charset=utf-8");
            xmlhttp.send(reqdata);
        }
 
        // 通用方法 获取url参数
        function _getQuery(key) {
            var query = location.href.split('?')[1],
                value = decodeURIComponent(query.split(key + "=")[1].split("&")[0]);
            return value;
        }
 
        //向process.php发送ajax请求
        function GetPerson(reqdata,callback) {
            var url = 'http://b.com/demo/ajax/ajaxproxy/process.php';
            var fn = function(data) {
                var proxy = document.getElementById('proxy');
                proxy.src = "http://a.com/demo/ajax/ajaxproxy/Proxy.html?data=" + encodeURIComponent(data) + "&callback=" + encodeURIComponent(callback);
            };
            _request(reqdata, url, fn);
        }
 
        (function(){
            var fn = _getQuery('fn'),
                reqdata = _getQuery("data"),
                callback = _getQuery("callback");
           eval(fn + "('" + reqdata +"', '" + callback + "')");
        })();
    </script>
</body>
</html>

这里其实就是接收来自request.html的请求得到请求参数和方法后向服务器process.php发出真正的ajax请求,然后将从服务器返回的数据以及从request.html传过来的回调函数名传递给proxy.html。 

接下来看看php代码如下,其实就是想返回一个json数据:

PHP

<?php $data = json_decode(file_get_contents("php://input")); header("Content-Type: application/json; charset=utf-8"); echo ('{"id" : ' . $data->id . ', "age" : 24, "sex" : "boy", "name" : "huangxueming"}'); ?>

1
2
3
4
5
<?php
    $data = json_decode(file_get_contents("php://input"));
    header("Content-Type: application/json; charset=utf-8");
    echo ('{"id" : ' . $data->id . ', "age" : 24, "sex" : "boy", "name" : "huangxueming"}');
?>

最后就是proxy.html代码:

XHTML

<!DOCTYPE HTML> <html> <head> <title> New Document </title> </head> <body> <script> function _getUrl(key) {//通用方法,获取URL参数 var query = location.href.split("?")[1], value = decodeURIComponent(query.split(key + "=")[1].split("&")[0]); return value; } (function() { var callback = _getUrl("callback"), data = _getUrl("data"); eval("window.top." + decodeURIComponent(callback) + "(" + decodeURIComponent(data) + ")"); })(); </script> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE HTML>
<html>
<head>
  <title> New Document </title>
</head>
<body>
    <script>
         function _getUrl(key) {//通用方法,获取URL参数
                       var query = location.href.split("?")[1],
                value = decodeURIComponent(query.split(key + "=")[1].split("&")[0]);
                    return value;
               }
         (function() {
             var callback = _getUrl("callback"),
                 data = _getUrl("data");
             eval("window.top." + decodeURIComponent(callback) + "(" + decodeURIComponent(data) + ")");
         })();
    </script>
</body>
</html>

这里也是最后一步了,proxy终于拿到了request.html透过response.html传过来的回调函数名以及从response.html直接传过来的响应数据,

利用window.top执行request.html里定义的回调函数。

四:iframe高度自适应的问题。

  iframe高度自适应分为2种,一种是同域下自适应  另外一种是跨域下自适应,下面我们来看看同域下iframe高度自适应的问题。

   1. 同域下iframe高度自适应的问题:

     思路:获取被嵌套iframe元素,通过JavaScript取得被嵌套页面最终高度,然后在主页面进行设置来实现。

     假如我们demo有iframe1.html和iframe2.html 下面贴上iframe1.html代码如下:

XHTML

<!DOCTYPE HTML> <html> <head> <title> New Document </title> <style> *{margin:0;padding:0;} </style> </head> <body> <iframe src="" style="width:100%;border:1px solid #333;" frameborder="0" id="iframe"></iframe> <script> window.onload = function() { var iframeid = document.getElementById('iframe'); if(iframeid && !window.opera) { if(iframeid.contentDocument && iframeid.contentDocument.body.offsetHeight) { iframeid.height = iframeid.contentDocument.body.offsetHeight; }else if(iframeid.Document && iframeid.Document.body.scrollHeight){ iframeid.height = iframeid.Document.body.scrollHeight; } } } </script> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE HTML>
<html>
<head>
  <title> New Document </title>
  <style>
    *{margin:0;padding:0;}
  </style>
</head>
 
<body>
    <iframe src="http://a.com/demo/ajax/iframeheight/iframe2.html" style="width:100%;border:1px solid #333;" frameborder="0" id="iframe"></iframe>
 
    <script>
        window.onload = function() {
            var iframeid = document.getElementById('iframe');
            if(iframeid && !window.opera) {
                if(iframeid.contentDocument && iframeid.contentDocument.body.offsetHeight) {
                    iframeid.height = iframeid.contentDocument.body.offsetHeight;
                }else if(iframeid.Document && iframeid.Document.body.scrollHeight){
                    iframeid.height = iframeid.Document.body.scrollHeight;
                }
            }
        }
    </script>
</body>
</html>

iframe2.html代码如下:

XHTML

<!DOCTYPE HTML> <html> <head> <title> New Document </title> <style> *{margin:0;padding:0;} </style> </head> <body> <div style="height:500px;"></div> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE HTML>
<html>
<head>
  <title> New Document </title>
  <style>
    *{margin:0;padding:0;}
  </style>
</head>
 
<body>
    <div style="height:500px;"></div>
</body>
</html>

就可以动态设置iframe1页面的高度为iframe2的高度了。

2. 跨域下iframe高度自适应的问题。

首先我们知道iframe跨域我们是不能用上面js方式来控制了,所以我们只能用个中间键,我们可以在a.com域下iframe1.html页面嵌套一个b.com域下的iframe2.html页面,然后我在iframe2.html页面嵌套个和iframe1.html相同域的iframe3.html页面了,这样的话 iframe1.html和iframe3.html就可以无障碍的进行通信了,因为页面iframe2.html嵌套iframe3.html,所以iframe2.html可以改写iframe3.html的href值。

 iframe1中的内容:

 iframe1.html内容主要接受iframe3.html页面传过来的内容并且去完成相应的操作。iframe1.html代码如下:

XHTML

<iframe src="" style="width:400px;height:200px;" id="iframe"></iframe> <script> var ifr_el = document.getElementById("iframe"); function getIfrData(data){ ifr_el.style.height = data+"px"; } </script>

1
2
3
4
5
6
7
<iframe src="http://b.com/demo/ajax/iframeheight/iframe2.html" style="width:400px;height:200px;" id="iframe"></iframe>
<script>
   var ifr_el = document.getElementById("iframe");
   function getIfrData(data){
    ifr_el.style.height = data+"px";
   }
</script>

iframe2.html中的内容:

iframe2.html内容是怎么把值传给iframe3.html页面,刚才说了是将值传递到iframe3.html页面的href中,所以只要修改iframe的src就可以,因为不用刷新C页面,所以可以用过hash的方式传递给iframe3.html页面.iframe2.html代码如下:

JavaScript

<!DOCTYPE HTML> <html> <head> <title> New Document </title> <style> *{margin:0;padding:0;} </style> </head> <body> <iframe id="iframe" src="" width="0" height="230px"></iframe> <script> var oldHeight = 0, ifr_el = document.getElementById("iframe"); t && clearInterval(t); var t = setInterval(function(){ var height = document.body.scrollHeight; if(oldHeight != height) { oldHeight = height; ifr_el.src += '#' +oldHeight; } },200); </script> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE HTML>
<html>
<head>
  <title> New Document </title>
  <style>
    *{margin:0;padding:0;}
  </style>
</head>
<body>
    <iframe id="iframe" src="http://a.com/demo/ajax/iframeheight/iframe3.html" width="0" height="230px"></iframe>
    <script>
        var oldHeight = 0,
              ifr_el = document.getElementById("iframe");
 
        t && clearInterval(t);
        var t = setInterval(function(){
            var height = document.body.scrollHeight;
            if(oldHeight != height) {
                oldHeight = height;
                ifr_el.src += '#' +oldHeight;
            }
        },200);
    </script>
</body>
</html>

可以看到 默认情况下 iframe1.html 页面我给iframe2.html的高度是200像素, 但是在iframe2.html我给iframe3.html高度是230像素,那么正常情况下是有滚动条的,那么现在我是想在iframe2.html获取滚动条的高度,把高度传给通过iframe3.html的src里面去,然后在iframe3.html页面里获取这个高度值 传给iframe1.html(因为iframe1.html和iframe3.html是同域的),所以iframe1.html能取到这个高度值,再设置下本身的高度就是这个值就ok了。iframe3.html页面的唯一功能就是接收iframe2.html页面通过href传进来的值并且传递给iframe1.html页面,可到iframe2.html页面传来的值可以通过一个定时器不停去查看location.href是 否被改变,但是这样感觉效率很低,还有个方式就是在新的浏览器中通过onhashchange事件 (IE8+,Chrome5.0+,Firefox3.6+,Safari5.0+,Opera10.6+)来监听href的改变。

iframe3.html代码如下:

JavaScript

<script> var oldHeight = 0; t && clearInterval(t); var t = setInterval(function(){ var height = location.href.split('#')[1]; if(height && height != oldHeight) { oldHeight = height; if(window.parent.parent.getIfrData) { window.parent.parent.getIfrData(oldHeight); } } },200); </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
    var oldHeight = 0;
    t && clearInterval(t);
    var t = setInterval(function(){
        var height = location.href.split('#')[1];
        if(height && height != oldHeight) {
            oldHeight = height;
            if(window.parent.parent.getIfrData) {
                window.parent.parent.getIfrData(oldHeight);
            }
        }
    },200);
</script>

这样就可以解决通过跨域实现iframe自适应高度的问题了。

五:本地存储cookie,sessionStorage, localStorage比较及使用

一:Cookie

1. 什么是cookie?

     Cookie是在客户端用于存储会话信息的,用户请求页面在web服务器与浏览器之间传递。每当同一台计算机通过浏览器请求某个页面时,就会发送这个 cookie。

 2. cookie的限制?

     1. Cookie的数据大小限制只能为4kb数据,如果数据长度超过4kb数据,超过后的数据将返回空字符串。

     2. Cookie是以文件形式存储在客户端计算机中,查看和修改cookie很方便,但是安全性方面不好,因此重要的数据不要使用cookie来存储。

     3. Cookie是有 有效期概念的,如果想要cookie存储多长时间,可以设置cookie的时间,一般的情况下,cookie的生命周期是在游览器关闭的时候失效。

     4. Cookie是有域的概念的,在不同的域下,cookie不能互相使用,cookie对于那个域是有效的,所有向该域发送的请求中都会包含这个cookie 的信息的,

    这个值可以包含子域(subdomain 如www.zuixiandao.cn) ,也可以不包含它(如.zuixiandao.cn, 对于所有的zuixiandao.cn的所有子域都有效). 

    如果没有明确的指定,那么这个域会被认作来自设置cookie的那个域。

     5. Cookie路径的概念:对于指定域中的那个路径,应该向服务器发送cookie,比如我们可以指定cookie只有从

     6. Cookie失效时间的概念:表示cookie何时应该被删除,默认情况下,浏览器会话结束时即将删除所有的cookie,不过也可以自己设置

 删除时间的。这个值是个GMT格式的日期(Wdy DD-Mon-YYYY HH:MM:SS GMT),用于指定应该删除cookie的准确时间,因此,

 cookie可在浏览器关闭后依然保存在用户的机器上(同一个浏览器,不同的浏览器不能保存),如果设置的日期是过期的日期,那么cookie立刻删掉。

      7. Cookie安全标志 指定后,cookie只有在使用SSL连接的时候才发送到服务器。比如:cookie信息只能发送给, 

  而

二: javascript中的cookie

 1. Javascript中的cookie是 一系列由分号隔开的名-值对,如下面的淘宝的cookie,如下:

document.cookie = “isg=E5AA5F2CEE8AA93BB351D1601F7B218E; thw=cn; _med=dw:1920&dh:1080&pw:1920&ph:1080&ist:0; v=0; t=1292efa78d867ff6275e6c5cb971bed7”;

     2. 设置cookie的超时。

         expires;   // 设置cookie的过期的时间

         以下设置 cookie 在 365天后超时;

         var date = new Date();

         date.setTime(date.getTime()+365*24*3600*1000);

         document.cookie = ‘key:value;expires =’ + date.toGMTString();

下面是设置cookie, 删除cookie,及 获取cookie的封装代码如下:

JavaScript

// 获取所有的cookies function getCookies() { var allCookies = document.cookie; return decodeURIComponent(allCookies); } // 获取指定的cookie function getOneCookie(name) { var allCookies = document.cookie.split(";"); for(var i = 0, ilen = allCookies.length; i < ilen; i++) { var temp = allCookies[i].split("="); if($.trim(decodeURIComponent(temp[0])) == name) { return decodeURIComponent(temp[1]); } } return -1; } // 添加cookie 有效期是一年 function addCookie(name,value,expires,path,domain,secure) { var curCookie = encodeURIComponent(name) + '=' + encodeURIComponent(value); if(expires instanceof Date) { curCookie += ';expires =' + expires.toGMTString(); }else { var date = new Date(); date.setTime(date.getTime()+365*24*3600*1000); curCookie += ';expires =' + date.toGMTString(); } if(path) { curCookie += "; path=" + path; } if(domain) { curCookie += "; domain=" +domain; } if(secure) { curCookie += "; secure"; } document.cookie = curCookie; } // 删除cookie function removeCookie(name,path,domain,secure) { addCookie(name,"",new Date(0),path,domain,secure); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 获取所有的cookies
function getCookies() {
    var allCookies = document.cookie;
    return decodeURIComponent(allCookies);
}
// 获取指定的cookie
function getOneCookie(name) {
    var allCookies = document.cookie.split(";");
    for(var i = 0, ilen = allCookies.length; i < ilen; i++) {
        var temp = allCookies[i].split("=");
        if($.trim(decodeURIComponent(temp[0])) == name) {
            return decodeURIComponent(temp[1]);
         }
    }
    return -1;
}
// 添加cookie 有效期是一年
function addCookie(name,value,expires,path,domain,secure) {
    var curCookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);
    if(expires instanceof Date) {
        curCookie += ';expires =' + expires.toGMTString();
    }else {
        var date = new Date();                
        date.setTime(date.getTime()+365*24*3600*1000);
        curCookie += ';expires =' + date.toGMTString();
    }
    if(path) {
        curCookie += "; path=" + path;
    }
    if(domain) {
        curCookie += "; domain=" +domain;
    }
    if(secure) {
        curCookie += "; secure";
    }
    document.cookie = curCookie;
}
// 删除cookie
function removeCookie(name,path,domain,secure) {
     addCookie(name,"",new Date(0),path,domain,secure);
}

下面我们来做一个小需求,比如一个登陆页面,有 有户名,密码,记住密码,及显示cookie和删除cookie按钮。当我点击记住密码的时候,那么当我第重启开页面时候,只要输入用户名,密码会自动填充,当然我们也可以点击删除cookie按钮进行删除,如下代码:

HTML代码:

XHTML

<h2>cookie介绍</h2> <p> <label>用户名:</label> <input type="text" class="userName" id="userName"/> </p> <p> <label>密码:</label> <input type="password" id="password"> </p> <p> <label>记住密码:</label> <input type="checkbox" id="remember"/> </p> <input value="删除" type="button" id="delCookie"> <input type="button" value="显示cookie" id="showpassword">

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<h2>cookie介绍</h2>
<p>
     <label>用户名:</label>
     <input type="text" class="userName" id="userName"/>
</p>
<p>
     <label>密码:</label>
     <input type="password" id="password">
</p>
<p>
     <label>记住密码:</label>
     <input type="checkbox" id="remember"/>
</p>
<input value="删除" type="button" id="delCookie">  
<input type="button" value="显示cookie" id="showpassword">

JS代码如下:

JavaScript

<script> // 获取所有的cookies function getCookies() { var allCookies = document.cookie; return allCookies; } // 获取指定的cookie function getOneCookie(name) { var allCookies = document.cookie.split(";"); for(var i = 0, ilen = allCookies.length; i < ilen; i++) { var temp = allCookies[i].split("="); if(temp[0] == decodeURIComponent(name)) { return decodeURIComponent(temp[1]); } } return -1; } // 添加cookie 有效期是一年 function addCookie(name,value,expires,path,domain,secure) { var curCookie = encodeURIComponent(name) + '=' + encodeURIComponent(value); if(expires instanceof Date) { curCookie += ';expires =' + expires.toGMTString(); }else { var date = new Date(); date.setTime(date.getTime()+365*24*3600*1000); curCookie += ';expires =' + date.toGMTString(); } if(path) { curCookie += "; path=" + path; } if(domain) { curCookie += "; domain=" +domain; } if(secure) { curCookie += "; secure"; } document.cookie = curCookie; } // 删除cookie function removeCookie(name,path,domain,secure) { addCookie(name,"",new Date(0),path,domain,secure); } $("#userName").unbind('blur').bind('blur',function(){ var val = $(this).val(); if(val) { var curCookie = getOneCookie(val); if(curCookie != -1) { $("#password").val(curCookie); } } }); // 记住密码 $("#remember").unbind('click').bind('click',function(){ if(document.getElementById("remember").checked) { if($("#userName").val() && $("#password").val()) { addCookie($("#userName").val(),$("#password").val()); alert("Saved!"); } } }); // 删除cookie $("#delCookie").unbind('click').bind('click',function() { if($("#userName").val()) { removeCookie($("#userName").val()); alert(getCookies()); }else { alert("用户名为空"); } }); // 显示cookie $("#showpassword").unbind('click').bind('click',function(){ if($("#userName").val()) { var curCookie = getOneCookie($("#userName").val()); if(curCookie != -1) { alert(curCookie); }else { alert("没有cookie"); } }else { alert("没有cookie"); } }); </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<script>
        // 获取所有的cookies
        function getCookies() {
            var allCookies = document.cookie;
            return allCookies;
        }
        // 获取指定的cookie
        function getOneCookie(name) {
            var allCookies = document.cookie.split(";");
            for(var i = 0, ilen = allCookies.length; i < ilen; i++) {
                var temp = allCookies[i].split("=");
                if(temp[0] == decodeURIComponent(name)) {
                    return decodeURIComponent(temp[1]);
                }
            }
            return -1;
        }
        // 添加cookie 有效期是一年
        function addCookie(name,value,expires,path,domain,secure) {
            var curCookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);
            if(expires instanceof Date) {
                curCookie += ';expires =' + expires.toGMTString();
            }else {
                var date = new Date();
                date.setTime(date.getTime()+365*24*3600*1000);
                curCookie += ';expires =' + date.toGMTString();
            }
            if(path) {
                curCookie += "; path=" + path;
            }
            if(domain) {
                curCookie += "; domain=" +domain;
            }
            if(secure) {
                curCookie += "; secure";
            }
            document.cookie = curCookie;
        }
        // 删除cookie
        function removeCookie(name,path,domain,secure) {
            addCookie(name,"",new Date(0),path,domain,secure);
        }
 
        $("#userName").unbind('blur').bind('blur',function(){
              var val = $(this).val();
              if(val) {
                 var curCookie = getOneCookie(val);
                 if(curCookie != -1) {
                    $("#password").val(curCookie);
                 }
              }
        });
        // 记住密码
        $("#remember").unbind('click').bind('click',function(){
            if(document.getElementById("remember").checked) {
                if($("#userName").val() && $("#password").val()) {
                    addCookie($("#userName").val(),$("#password").val());  
                    alert("Saved!");
                }
 
            }
        });
        // 删除cookie
        $("#delCookie").unbind('click').bind('click',function() {
            if($("#userName").val()) {
                removeCookie($("#userName").val());
                alert(getCookies());
            }else {
                alert("用户名为空");
            }
        });
 
        // 显示cookie
        $("#showpassword").unbind('click').bind('click',function(){
            if($("#userName").val()) {
                var curCookie = getOneCookie($("#userName").val());
                if(curCookie != -1) {
                    alert(curCookie);
                }else {
                    alert("没有cookie");
                }
 
            }else {
                alert("没有cookie");
            }
        });
</script>

Cookie的实例demo如下:

cookie

三:IE用户数据;

在IE5.0中,微软通过一个自定义行为引入了持久化用户数据的概念,用户数据允许每个文档最多128kb的数据,每个域名最多1MB的数据,

要使用持久化数据,首先必须如下所示,使用css在某个元素上指定userData行为:

 

IE用户数据

 

针对IE有如下使用方法:

1. getAttribute(“key”) 获取指定的属性值。

2. load(object) 从 userData 存储区载入存储的对象数据。

3. removeAttribute(“key”) 移除对象的指定属性。

4. save(object) 将对象数据存储到一个 userData 存储区。

5. setAttribute(“key”,”value”) 设置指定的属性值。

我们继续做一个demo来演示下在IE浏览器下的存储的demo。

HTML代码如下:

XHTML

<div style="behavior:url(#default#userData)" id="dataStore">IE用户数据</div> <input value="IE下保存数据" type="button" id="IESave"> <input type="button" value="IE下获取数据" id="IEGet"> <input type="button" value="IE下删除数据" id="IERemove">

1
2
3
4
<div style="behavior:url(#default#userData)" id="dataStore">IE用户数据</div>
<input value="IE下保存数据" type="button" id="IESave">
<input type="button" value="IE下获取数据" id="IEGet">
<input type="button" value="IE下删除数据" id="IERemove">

JS代码如下:

JavaScript

var dataStore = document.getElementById("dataStore"); $("#IESave").click(function(e){ dataStore.setAttribute("name","tugenhua"); dataStore.setAttribute("book",'111111'); dataStore.save("bookInfo"); }); // IE下获取数据 $("#IEGet").click(function(){ dataStore.load("bookInfo"); alert(dataStore.getAttribute("name")); alert(dataStore.getAttribute("book")); }); // IE下删除数据 $("#IERemove").click(function(){ dataStore.removeAttribute("name"); dataStore.removeAttribute("book"); dataStore.save("bookInfo"); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var dataStore = document.getElementById("dataStore");
$("#IESave").click(function(e){
    dataStore.setAttribute("name","tugenhua");
    dataStore.setAttribute("book",'111111');
    dataStore.save("bookInfo");
});
// IE下获取数据
$("#IEGet").click(function(){
    dataStore.load("bookInfo");
    alert(dataStore.getAttribute("name"));
    alert(dataStore.getAttribute("book"));
});
 
// IE下删除数据
$("#IERemove").click(function(){
    dataStore.removeAttribute("name");
    dataStore.removeAttribute("book");
    dataStore.save("bookInfo");
});

IE浏览器下的demo如下:

使用IE浏览器下查看效果 请点击我!!

四:sessionStorage 和 localStorage 

Html5新增了两个本地存储数据,分别是sessionStorage 和 localStorage.

浏览器支持程度如下:

图片 4

注意:IE8 及 以上都支持 web storage。

   sessionStorage: 将数据保存在session对象中,所谓session,指用户浏览某个网站时,从进入网站到浏览器关闭的这段时间,也就是用户浏览这个网站所花费的时间。

       生命周期:指只在当前的窗口有效,打开一个新的同源窗口,或者说重启浏览器都失效。

       数据大小:可以保存5MB甚至更多。

   localStorage: 将数据保存在客户端本地的硬件设备(通常是指硬盘,但也可以是其他硬件设备),即使浏览器被关闭了,该数据依然存在,下次打开浏览器访问网站时仍然可以继续使用。但是,数据保存是按不同的浏览器分别进行的,也就是说,如果打开别的浏览器,是读取不到在这个浏览器中保存的数据的。

     生命周期:数据一直保存在硬盘中。持久性保存(但是不同的浏览器保存的数据,是不能通用的)。

     数据大小:可以保存5MB甚至更多的数据。

    1. cookie 与 sessionStorage 及 localStorage的区别;   

        共同点:都是在客户端存储数据,且是同源的。

    区别:

存储大小不一样;cookie存储数据最大只能为4kb,而sessionStorage与localStorage可以保存5MB甚至更多数据。

  Cookie数据始终在同源的http请求中携带,即cookie在浏览器与服务器之间来回传递,而sessionStorage与localStorage不会自动发给服务端,仅在本地保存。

数据有效期不同;sessionStorage仅在当前浏览器窗口未关闭之前有效(同源的新窗口不生效),localStorage仅在当前的浏览器下永久生效(不同的浏览器不能共享数据),不管关闭了 重新打开的 还是生效的。Cookie只在设置的cookie过期时间之前一直有效,即使窗口或者浏览器关闭,或者打开新的同源窗口。

作用域不同;sessionStorage不在不同的浏览器窗口中共享,即是同一个页面,localStorage在所有的同源窗口中都是共享的(只在相同的浏览器下),cookie在所有的同源窗口都是共享的(仅在同一个浏览器中)。

      SessionStorage与LocalStorage他们都拥有相同的方法;

      1. setItem存储value

         用法:.setItem( key, value),代码如下:

         localStorage.setItem(key,value):将value存储到key字段

      2. getItem获取value

          用法:.getItem(key) 代码如下:

          localStorage.getItem(key):获取指定key本地存储的值

      3. removeItem删除key

          用法:.removeItem(key),代码如下:

          localStorage.removeItem(key):删除指定key本地存储的值

      4. clear清除所有的key/value

          用法:.clear(),代码如下:

          localStorage.clear();  清除所有的数据(firefox除外)

      它将删除所有同源的本地存储的localStorage数据

      而对于Session Storage,它只清空当前会话存储的数据。

      sessionStorage也有上面一样的方法;

下面我们来使用sessionStorage及 localStorage 来练习下,来做个demo。如下:

HTML代码如下:

XHTML

<h1>web Storage实列</h1> <p id="msg"></p> <input type="text" id="input" /> <input type="button" value="保存数据" id="saveData"/> <input type="button" value="读取数据" id="readData"/> <input type="button" value="删除数据" id="removeData"/> <input type="button" value="清除所有的数据" id="clearData"/>

1
2
3
4
5
6
7
<h1>web Storage实列</h1>
<p id="msg"></p>
<input type="text" id="input" />
<input type="button" value="保存数据" id="saveData"/>
<input type="button" value="读取数据" id="readData"/>
<input type="button" value="删除数据" id="removeData"/>
<input type="button" value="清除所有的数据" id="clearData"/>

页面上一个input输入框,当我点击 保存数据 按钮后 分别使用sessionStorage和localStorage 把值保存起来,当我点击 读取数据 按钮后 读取数据,分别在不同的浏览器或者新的同源窗口 或者关闭浏览器窗口 重新打开新窗口,来分别看看之间的区别,区别上面已经总结了,下面我们来看看JS代码如下:

JavaScript

<script> // sessionStorage demo $("#saveData").unbind('click').bind('click',function(){ var inputVal = $("#input").val(); sessionStorage.setItem("message",inputVal); //localStorage.setItem("message",inputVal); }); $("#readData").unbind("click").bind('click',function(){ var msg = sessionStorage.getItem("message"); //var msg = localStorage.getItem("message"); $("#msg").html(msg); }); $("#removeData").unbind('click').bind('click',function(){ sessionStorage.removeItem("message"); //localStorage.removeItem("message"); }); $("#clearData").unbind('click').bind('click',function(){ sessionStorage.clear(); //localStorage.clear(); }); </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<script>
        // sessionStorage demo
        $("#saveData").unbind('click').bind('click',function(){
            var inputVal = $("#input").val();
            sessionStorage.setItem("message",inputVal);
            //localStorage.setItem("message",inputVal);
        });
        $("#readData").unbind("click").bind('click',function(){
            var msg = sessionStorage.getItem("message");
            //var msg = localStorage.getItem("message");
            $("#msg").html(msg);
        });
        $("#removeData").unbind('click').bind('click',function(){
            sessionStorage.removeItem("message");
            //localStorage.removeItem("message");
        });
        $("#clearData").unbind('click').bind('click',function(){
            sessionStorage.clear();
            //localStorage.clear();
        });
</script>

如上的代码,我们现在继续来看看效果如下:使用

sessionStorage效果请点击:

使用localStorage效果请点击:

我们还可以做一点复杂的应用,比如如下一个表格有一些字段,比如姓名,email,tel,及备注字段,我们先保存到本地去,然后根据姓名这个字段进行搜索就可以搜索到数据到,我们可以称为这是简单的本地数据库,如下代码:

XHTML

<table> <tr> <td>姓名:</td> <td> <input type="text" id="name"/> </td> </tr> <tr> <td>EMALL:</td> <td> <input type="text" id="email"/> </td> </tr> <tr> <td>电话号码:</td> <td> <input type="text" id="tel"/> </td> </tr> <tr> <td>备注:</td> <td> <input type="text" id="memo"/> </td> </tr> <tr> <td>保存</td> <td> <input type="button" id="save" value="保存"/> </td> </tr> </table> <p> 检索:<input type="text" id="file"/> <input type="button" id="find" value="检索"/> </p> <p id="msg"></p>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<table>
    <tr>
        <td>姓名:</td>
        <td>
            <input type="text" id="name"/>
        </td>
    </tr>
    <tr>
        <td>EMALL:</td>
        <td>
            <input type="text" id="email"/>
        </td>
    </tr>
    <tr>
        <td>电话号码:</td>
        <td>
            <input type="text" id="tel"/>
        </td>
    </tr>
    <tr>
        <td>备注:</td>
        <td>
            <input type="text" id="memo"/>
        </td>
    </tr>
    <tr>
        <td>保存</td>
        <td>
           <input type="button" id="save" value="保存"/>
        </td>
    </tr>
</table>
<p>
     检索:<input type="text" id="file"/>
     <input type="button" id="find" value="检索"/>
</p>
<p id="msg"></p>

JS代码如下:

JavaScript

// 保存数据 $("#save").unbind('click').bind('click',function(){ var data = new Object; data.name = $("#name").val(); data.email = $("#email").val(); data.tel = $("#tel").val(); data.memo = $("#memo").val(); var str = JSON.stringify(data); localStorage.setItem(data.name,str); alert("数据已经保存"); }); // 检索数据 $("#find").unbind('click').bind('click',function(){ var find = $("#file").val(); var str = localStorage.getItem(find); var data = JSON.parse(str); var result = "姓名:" + data.name + "</br>"; result += "Email: " + data.email + "</br>"; result += "tel:" + data.tel + "</br>"; result += "备注:" + data.memo + "</br>"; $("#msg").html(result); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//  保存数据
$("#save").unbind('click').bind('click',function(){
     var data = new Object;
     data.name = $("#name").val();
     data.email = $("#email").val();
     data.tel = $("#tel").val();
     data.memo = $("#memo").val();
     var str = JSON.stringify(data);
     localStorage.setItem(data.name,str);
     alert("数据已经保存");
});
 
// 检索数据
$("#find").unbind('click').bind('click',function(){
      var find = $("#file").val();
      var str = localStorage.getItem(find);
      var data = JSON.parse(str);
      var result = "姓名:" + data.name + "</br>";
          result += "Email: " + data.email + "</br>";
          result += "tel:" + data.tel + "</br>";
          result += "备注:" + data.memo + "</br>";
      $("#msg").html(result);
  });

demo如下效果:

请点击查看:

六:window.name 实现跨域数据传输。

Window.name 中的name值在不同的页面(甚至不同的域名)加载后依旧存在,并且数据量可以达到2MB。

Window.name 数据传输的基本原理:

同域下:Name在浏览器环境中是一个全局/window对象的属性,且当在ifrmae中加载页面时,name的属性值依旧保持不变。

比如我们在同域下abc.example.com下 有2个页面 app.html 和 data.html

 App.html页面代码嵌套一个iframe data.html页面,代码如下:

XHTML

<iframe src="" id="iframe"/>

1
<iframe src="http://abc.example.com/demo/tugenhua0707/storage/data.html" id="iframe"/>

其中data.html 页面 使用一个window.name = “111”;来保存数据。

   现在我们接下来在app.html页面 如何来调用同域下的data.html下的window.name的数据,首先我们先要获取到这个iframe,然后判断iframe是否加载完,加载完后就获取这个iframe中的window.name, 

App.html JS的代码如下:

JavaScript

function iframeIsLoad(iframe,callback){ if(iframe.attachEvent) { iframe.attachEvent('onload',function(){ callback & callback(); }); }else { iframe.onload = function(){ callback & callback(); } } } var iframe = document.getElementById("iframe"); // 同域下 iframeIsLoad(iframe,function(){ var data = iframe.contentWindow.name; alert(data); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function iframeIsLoad(iframe,callback){
    if(iframe.attachEvent) {
         iframe.attachEvent('onload',function(){
          callback & callback();
         });
    }else {
        iframe.onload = function(){
         callback & callback();
        }
    }
}
var iframe = document.getElementById("iframe");
// 同域下
iframeIsLoad(iframe,function(){
    var data = iframe.contentWindow.name;
        alert(data);
});

2. 跨域下:

   现在我们使用hosts文件来绑定2个IP 来演示下跨域的情况,在hosts文件绑定如下:

   127.0.0.1  abc.example.com  和 127.0.0.1 def.example.com

   我们现在在 abc.example.com 新建一个app.html页面 里面还是嵌套一个 def.example.com域下的 data.html页面,代码如下:

   App.html代码如下:

XHTML

<iframe src="" id="iframe"/>

1
<iframe src="http://def.example.com/demo/tugenhua0707/storage/data.html" id="iframe"/>

如果我们还是和上面的方式取数据的话 明显报错跨域了,现在我们是使用window.name解决跨域下数据的传输,那么我们可以使用一个同域abc.example.com下的代理页面proxy.html来做处理,通过在def.example.com域下的data.html页面加载一个与abc.example.com同域下的proxy.html页面, 将该目标页面设置iframe的name属性,因为app.html 与 proxy.html是在同一个域下,所以我们可以获取到。

在app.html页面 JS代码如下:

JavaScript

function iframeIsLoad(iframe,callback){ if(iframe.attachEvent) { iframe.attachEvent('onload',function(){ callback & callback(); }); }else { iframe.onload = function(){ callback & callback(); } } } var iframe = document.getElementById("iframe"); var state = 0; // 跨域下 iframeIsLoad(iframe,function(){ if (state === 1) { var data = iframe.contentWindow.name; // 读取数据 alert(data); //弹出111 } else if (state === 0) { state = 1; iframe.contentWindow.location = ""; // 设置的代理文件 } });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function iframeIsLoad(iframe,callback){
    if(iframe.attachEvent) {
        iframe.attachEvent('onload',function(){
             callback & callback();
        });
    }else {
        iframe.onload = function(){
             callback & callback();
         }
     }
}      
var iframe = document.getElementById("iframe");
var state = 0;
// 跨域下
iframeIsLoad(iframe,function(){
   if (state === 1) {
        var data = iframe.contentWindow.name;    // 读取数据
        alert(data);    //弹出111
   } else if (state === 0) {
        state = 1;
        iframe.contentWindow.location = "http://abc.example.com/demo/tugenhua0707/storage/proxy.html";    // 设置的代理文件
   }  
});

当然如上:我们如果name数据已经拿到了的话,以后不需要的话,我们可以销毁掉,清空等操作。

七:使用HTML5中postMessage 实现ajax中的POST跨域问题

浏览器支持程度:IE8+,firefox4+,chrome8+  opera10+

     1. 首先,要想接收从其他的窗口发过来的消息,就必须对窗口对象的message事件进行监听,如下代码:

          window.addEventListener(“message”, function(){},false);

     2. 其次,需要使用window对象的postMessage方法向其他窗口发送消息,该方法定义如下所示:

         otherWindow.postMessage(message, targetOrigin);

该方法使用2个参数,第一个参数为所发送的消息文本,但也可以是任何javascript对象,第二个参数是接收消息的对象窗口的url地址

(比如:http:127.0.0.1:8080/) , 但是我们也可以在url地址字符串中使用通配符”*”, 指定全部的域下,但是我们还是建议使用特定的域名下,

otherWindow为要发送窗口对象的引用。

Demo演示:

     假如现在我在hosts文件下 ,绑定2 个域名如下:

     127.0.0.1       abc.example.com

     127.0.0.1        longen.example.com

现在假如在abc.example.com域下有一个abc.html页面,在longen.example.com域下有def.html页面,现在我是希望这2个不同域名下的页面

能互相通信,abc.html代码如下:

XHTML

<form> <p> <label for="message" style="color:red;font-size:24px;">给iframe子窗口发一个信息:</label> <input type="text" name="message" value="send" id="message" /> <input type="submit" value="submit" id="submit"/> </p> </form> <h4>目标iframe传来的信息:</h4> <p id="test">暂无信息</p> <iframe id="iframe" src="" style="display:none"></iframe>

1
2
3
4
5
6
7
8
9
10
<form>  
      <p>  
        <label for="message" style="color:red;font-size:24px;">给iframe子窗口发一个信息:</label>  
        <input type="text" name="message" value="send" id="message" />  
        <input type="submit" value="submit" id="submit"/>  
      </p>  
</form>  
<h4>目标iframe传来的信息:</h4>  
<p id="test">暂无信息</p>  
<iframe id="iframe" src="http://longen.example.com/webSocket/def.html" style="display:none"></iframe>

JS代码如下:

JavaScript

var win = document.getElementById("iframe").contentWindow; document.getElementById("submit").onclick = function(e){ e.preventDefault(); win.postMessage(document.getElementById("message").value,""); } window.addEventListener("message",function(e){ e.preventDefault(); document.getElementById("test").innerHTML = "从" + e.origin + "那里传过来的消息:n" + e.data; },false);

1
2
3
4
5
6
7
8
9
10
var win = document.getElementById("iframe").contentWindow;    
document.getElementById("submit").onclick = function(e){
    e.preventDefault();
    win.postMessage(document.getElementById("message").value,"http://longen.example.com");
}  
 
window.addEventListener("message",function(e){
     e.preventDefault();
     document.getElementById("test").innerHTML = "从" + e.origin + "那里传过来的消息:n" + e.data;
},false);

Def.html代码如下:

HTML代码:

XHTML

<form> <p> <label for="message">给父窗口abc.html发个信息:</label> <input type="text" name="message" value="send" id="message" /> <input type="submit" /> </p> </form> <p id="test2">暂无信息。</p>

1
2
3
4
5
6
7
8
<form>  
      <p>  
        <label for="message">给父窗口abc.html发个信息:</label>  
        <input type="text" name="message" value="send" id="message" />  
        <input type="submit" />  
      </p>  
</form>  
<p id="test2">暂无信息。</p>

JS代码如下:

JavaScript

var parentwin = window.parent; window.addEventListener("message",function(e){ document.getElementById("test2").innerHTML = "从父窗口传来的域" +e.origin + ",和内容数据:" + e.data; parentwin.postMessage('HI!你给我发了"'+e.data+'"。',""); },false);

1
2
3
4
5
var parentwin = window.parent;
window.addEventListener("message",function(e){
       document.getElementById("test2").innerHTML = "从父窗口传来的域" +e.origin + ",和内容数据:" + e.data;  
       parentwin.postMessage('HI!你给我发了"'+e.data+'"。',"http://abc.example.com");
},false);

当我点击abc.html页面后,可以看到效果如下,从def.html返回内容了。如下:

图片 5

我们需要知道如下几条信息:

1. 通过对window对象的message事件进行监听,可以接收消息。

2. 通过访问message事件的origin属性,可以获取消息的发送源。

3. 通过访问message事件的data属性,可以取得消息内容。

4. 使用postMessage方法发送消息。

5. 通过访问message事件的source属性,可以获取消息发送源的窗口对象(准确的说,应该是窗口的代理对象)。

有了上面的基本知识点,我们可以延伸为实现ajax POST跨域的问题。

2. 使用postMessage 知识点解决 ajax中POST跨域问题。

 原理:原理也很简单,假如我们的域名abc.example.com下的abc.html页面需要发ajax请求(跨域,域名为longen.example.com)下,那么我们还是先跨页面文档的形式,和上面一样,我们可以现在longen.example.com下 建立一个页面,比如叫def.html. 那么我们现在还是在 abc.html 页面嵌入一个隐藏域iframe src路径指向longen.example.com域下def,html页面。过程还是和跨文档类似,

 只是现在在def.html页面中 在window.onmessage 事件内写ajax请求即可,如下代码:

abc.example.com下的abc.html页面如下:

html代码和上面一样,下面是JS代码:

JavaScript

var win = document.getElementById("iframe").contentWindow; document.getElementById("submit").onclick = function(e){ e.preventDefault(); win.postMessage(document.getElementById("message").value,""); } window.addEventListener("message",function(e){ e.preventDefault(); alert(typeof e.data) var json = JSON.parse(e.data); console.log(json); alert(json.url) },false);

1
2
3
4
5
6
7
8
9
10
11
12
var win = document.getElementById("iframe").contentWindow;      
document.getElementById("submit").onclick = function(e){
      e.preventDefault();
      win.postMessage(document.getElementById("message").value,"http://longen.example.com/");
}    
window.addEventListener("message",function(e){
    e.preventDefault();
    alert(typeof e.data)
    var json = JSON.parse(e.data);
     console.log(json);
    alert(json.url)
},false);

def.html代码如下:

JS代码如下:

JavaScript

//获取跨域数据 window.onmessage = function(e){ $.ajax({ url: '', type:'POST', dataType:'text', //data: {msg:e.data}, success: function(res) { var parentwin = window.parent; parentwin.postMessage(res," } }); };

1
2
3
4
5
6
7
8
9
10
11
12
13
//获取跨域数据  
window.onmessage = function(e){  
     $.ajax({
          url: 'http://longen.example.com/webSocket/test.php',
          type:'POST',
          dataType:'text',
          //data: {msg:e.data},
          success: function(res) {
               var parentwin = window.parent;  
               parentwin.postMessage(res,"http://abc.example.com");//跨域发送数据  
          }
      });
};

test.php代码如下:

PHP

<?php $data=array( url =>1, name =>'2', 'xx-xx'=>"xx" ); echo json_encode($data); ?>

1
2
3
4
5
6
7
8
<?php
    $data=array(  
     url =>1,
      name =>'2',
      'xx-xx'=>"xx"
);
echo json_encode($data);
?>

如上实现方式 就可以实现ajax post跨域了。

1 赞 8 收藏 1 评论

图片 6

在js中常用的跨域请求包括有四种,分别为:window.name、JSONP、jQuery.getJSON、flash跨域这种方法,第一种是利用iframe,第二与三种使用的是json数据,最后一种是xml文件操作,下面我来简单介绍一下。

本文章来给大家总结一下关于在js中框架(iframe)之间相互传值程序代码,从我们最常用的办法到我写了一个函数及后面的iframe跨域传值的一些方法总结。

什么是跨域?

前端常见跨域解决方案(全)

2017/09/14 · 基础技术 · 3 评论 · 跨域

原文出处: 安静de沉淀   

一、window.name

很多框架存在父子关系,操作起来十分麻烦,很多同学经常出现这样悲催的代码:

 

什么是跨域?

跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。

广义的跨域:

1.) 资源跳转: A链接、重定向、表单提交 2.) 资源嵌入:<link>、<script>、<img>、<frame>等dom标签,还有样式中background:url()、@font-face()等文件外链 3.) 脚本请求: js发起的ajax请求、dom和js对象的跨域操作等

1
2
3
1.) 资源跳转: A链接、重定向、表单提交
2.) 资源嵌入:<link>、<script>、<img>、<frame>等dom标签,还有样式中background:url()、@font-face()等文件外链
3.) 脚本请求: js发起的ajax请求、dom和js对象的跨域操作等

其实我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景。

什么是同源策略?
同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指”协议+域名+端口”三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

同源策略限制以下几种行为:

1.) Cookie、LocalStorage 和 IndexDB 无法读取 2.) DOM 和 Js对象无法获得 3.) AJAX 请求不能发送

1
2
3
1.) Cookie、LocalStorage 和 IndexDB 无法读取
2.) DOM 和 Js对象无法获得
3.) AJAX 请求不能发送

1、 服务器返回

 代码如下

跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。

常见跨域场景

URL 说明 是否允许通信 同一域名,不同文件或路径 允许 同一域名,不同端口 不允许 同一域名,不同协议 不允许 域名和域名对应相同ip 不允许 主域相同,子域不同 不允许 不同域名 不允许

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
URL                                      说明                    是否允许通信
http://www.domain.com/a.js
http://www.domain.com/b.js         同一域名,不同文件或路径           允许
http://www.domain.com/lab/c.js
 
http://www.domain.com:8000/a.js
http://www.domain.com/b.js         同一域名,不同端口                不允许
http://www.domain.com/a.js
https://www.domain.com/b.js        同一域名,不同协议                不允许
http://www.domain.com/a.js
http://192.168.4.12/b.js           域名和域名对应相同ip              不允许
http://www.domain.com/a.js
http://x.domain.com/b.js           主域相同,子域不同                不允许
http://domain.com/c.js
http://www.domain1.com/a.js
http://www.domain2.com/b.js        不同域名                         不允许

 代码如下

复制代码

 

跨域解决方案

1、 通过jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域

复制代码

window.parent.document.getElementById("main")
.contentWindow.document.getElementById('input').value =
document.getElementById('myIframe')
.contentWindow.document.getElementById('s0').value;

广义的跨域:

一、 通过jsonp跨域

通常为了减轻web服务器的负载,我们把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。

1.)原生实现:

<script> var script = document.createElement('script'); script.type = 'text/javascript'; // 传参并指定回调执行函数为onBack script.src = ''; document.head.appendChild(script); // 回调执行函数 function onBack(res) { alert(JSON.stringify(res)); } </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
    var script = document.createElement('script');
    script.type = 'text/javascript';
 
    // 传参并指定回调执行函数为onBack
    script.src = 'http://www.domain2.com:8080/login?user=admin&callback=onBack';
    document.head.appendChild(script);
 
    // 回调执行函数
    function onBack(res) {
        alert(JSON.stringify(res));
    }
</script>

服务端返回如下(返回时即执行全局函数):

onBack({"status": true, "user": "admin"})

1
onBack({"status": true, "user": "admin"})

2.)jquery ajax:

$.ajax({ url: '', type: 'get', dataType: 'jsonp', // 请求方式为jsonp jsonpCallback: "onBack", // 自定义回调函数名 data: {} });

1
2
3
4
5
6
7
$.ajax({
    url: 'http://www.domain2.com:8080/login',
    type: 'get',
    dataType: 'jsonp',  // 请求方式为jsonp
    jsonpCallback: "onBack",    // 自定义回调函数名
    data: {}
});

3.)vue.js:

this.$http.jsonp('', { params: {}, jsonp: 'onBack' }).then((res) => { console.log(res); })

1
2
3
4
5
6
this.$http.jsonp('http://www.domain2.com:8080/login', {
    params: {},
    jsonp: 'onBack'
}).then((res) => {
    console.log(res);
})

后端node.js代码示例:

var querystring = require('querystring'); var http = require('http'); var server = http.createServer(); server.on('request', function(req, res) { var params = qs.parse(req.url.split('?')[1]); var fn = params.callback; // jsonp返回设置 res.writeHead(200, { 'Content-Type': 'text/javascript' }); res.write(fn + '(' + JSON.stringify(params) + ')'); res.end(); }); server.listen('8080'); console.log('Server is running at port 8080...');

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var querystring = require('querystring');
var http = require('http');
var server = http.createServer();
 
server.on('request', function(req, res) {
    var params = qs.parse(req.url.split('?')[1]);
    var fn = params.callback;
 
    // jsonp返回设置
    res.writeHead(200, { 'Content-Type': 'text/javascript' });
    res.write(fn + '(' + JSON.stringify(params) + ')');
 
    res.end();
});
 
server.listen('8080');
console.log('Server is running at port 8080...');

jsonp缺点:只能实现get一种请求。

<script>window.name=’{“id”:”3″, “name”:”leisure”}’;</script>

看一个我自己做的实例

 

二、 document.domain + iframe跨域

此方案仅限主域相同,子域不同的跨域应用场景。

实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。

1.)父窗口:(

<iframe id="iframe" src="; <script> document.domain = 'domain.com'; var user = 'admin'; </script>

1
2
3
4
5
<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
<script>
    document.domain = 'domain.com';
    var user = 'admin';
</script>

2.)子窗口:(

<script> document.domain = 'domain.com'; // 获取父窗口中变量 alert('get js data from parent ---> ' + window.parent.user); </script>

1
2
3
4
5
<script>
    document.domain = 'domain.com';
    // 获取父窗口中变量
    alert('get js data from parent ---> ' + window.parent.user);
</script>

2、定义一个iframe,添加onload事件 <iframe id=”iframe1″ onload=”iLoad”><iframe>

iframe的调用包括以下几个方面:(调用包含html dom,js全局变量,js方法)

1.) 资源跳转: A链接、重定向、表单提交

三、 location.hash + iframe跨域

实现原理: a欲与b跨域相互通信,通过中间页c来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接js访问来通信。

具体实现:A域:a.html -> B域:b.html -> A域:c.html,a与b不同域只能通过hash值单向通信,b与c也不同域也只能单向通信,但c与a同域,所以c可通过parent.parent访问a页面所有对象。

1.)a.html:(

<iframe id="iframe" src="" style="display:none;"></iframe> <script>     var iframe = document.getElementById('iframe');     // 向b.html传hash值     setTimeout(function() {         iframe.src = iframe.src + '#user=admin';     }, 1000);          // 开放给同域c.html的回调方法     function onCallback(res) {         alert('data from c.html ---> ' + res);     } </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe&gt
<script>
    var iframe = document.getElementById('iframe');
 
    // 向b.html传hash值
    setTimeout(function() {
        iframe.src = iframe.src + '#user=admin';
    }, 1000);
    
    // 开放给同域c.html的回调方法
    function onCallback(res) {
        alert('data from c.html ---> ' + res);
    }
</script>

2.)b.html:(

<iframe id="iframe" src="" style="display:none;"></iframe> <script>     var iframe = document.getElementById('iframe');     // 监听a.html传来的hash值,再传给c.html     window.onhashchange = function () {         iframe.src = iframe.src + location.hash;     }; </script>

1
2
3
4
5
6
7
8
9
<iframe id="iframe" src="http://www.domain1.com/c.html" style="display:none;"></iframe>
<script>
    var iframe = document.getElementById('iframe');
 
    // 监听a.html传来的hash值,再传给c.html
    window.onhashchange = function () {
        iframe.src = iframe.src + location.hash;
    };
</script>

3.)c.html:(

<script>     // 监听b.html传来的hash值     window.onhashchange = function () {         // 再通过操作同域a.html的js回调,将结果传回         window.parent.parent.onCallback('hello: ' + location.hash.replace('#user=', ''));     }; </script>

1
2
3
4
5
6
7
<script>
    // 监听b.html传来的hash值
    window.onhashchange = function () {
        // 再通过操作同域a.html的js回调,将结果传回
        window.parent.parent.onCallback('hello: ' + location.hash.replace('#user=', ''));
    };
</script>

 代码如下

主页面调用iframe;

2.) 资源嵌入:<link>、<script>、<img>、<frame>等dom标签,还有样式中background:url()、@font-face()等文件外链

四、 window.name + iframe跨域

window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。

1.)a.html:(

var proxy = function(url, callback) { var state = 0; var iframe = document.createElement('iframe'); // 加载跨域页面 iframe.src = url; // onload事件会触发2次,第1次加载跨域页,并留存数据于window.name iframe.onload = function() { if (state === 1) { // 第2次onload(同域proxy页)成功后,读取同域window.name中数据 callback(iframe.contentWindow.name); destoryFrame(); } else if (state === 0) { // 第1次onload(跨域页)成功后,切换到同域代理页面 iframe.contentWindow.location = ''; state = 1; } }; document.body.appendChild(iframe); // 获取数据以后销毁这个iframe,释放内存;这也保证了安全(不被其他域frame js访问) function destoryFrame() { iframe.contentWindow.document.write(''); iframe.contentWindow.close(); document.body.removeChild(iframe); } }; // 请求跨域b页面数据 proxy('', function(data){ alert(data); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var proxy = function(url, callback) {
    var state = 0;
    var iframe = document.createElement('iframe');
 
    // 加载跨域页面
    iframe.src = url;
 
    // onload事件会触发2次,第1次加载跨域页,并留存数据于window.name
    iframe.onload = function() {
        if (state === 1) {
            // 第2次onload(同域proxy页)成功后,读取同域window.name中数据
            callback(iframe.contentWindow.name);
            destoryFrame();
 
        } else if (state === 0) {
            // 第1次onload(跨域页)成功后,切换到同域代理页面
            iframe.contentWindow.location = 'http://www.domain1.com/proxy.html';
            state = 1;
        }
    };
 
    document.body.appendChild(iframe);
 
    // 获取数据以后销毁这个iframe,释放内存;这也保证了安全(不被其他域frame js访问)
    function destoryFrame() {
        iframe.contentWindow.document.write('');
        iframe.contentWindow.close();
        document.body.removeChild(iframe);
    }
};
 
// 请求跨域b页面数据
proxy('http://www.domain2.com/b.html', function(data){
    alert(data);
});

2.)proxy.html:(http://www.domain1.com/proxy….)
中间代理页,与a.html同域,内容为空即可。

3.)b.html:(

<script>     window.name = 'This is domain2 data!'; </script>

1
2
3
<script>
    window.name = 'This is domain2 data!';
</script>

总结:通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

复制代码

iframe页面调用主页面;

3.) 脚本请求: js发起的ajax请求、dom和js对象的跨域操作等

五、 postMessage跨域

postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
a.) 页面和其打开的新窗口的数据传递
b.) 多窗口之间消息传递
c.) 页面与嵌套的iframe消息传递
d.) 上面三个场景的跨域数据传递

用法:postMessage(data,origin)方法接受两个参数
data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
origin: 协议+主机+端口号,也可以设置为”*”,表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为”/”。

1.)a.html:(

<iframe id="iframe" src="" style="display:none;"></iframe> <script> var iframe = document.getElementById('iframe'); iframe.onload = function() { var data = { name: 'aym' }; // 向domain2传送跨域数据 iframe.contentWindow.postMessage(JSON.stringify(data), ''); }; // 接受domain2返回数据 window.addEventListener('message', function(e) { alert('data from domain2 ---> ' + e.data); }, false); </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>      
    var iframe = document.getElementById('iframe');
    iframe.onload = function() {
        var data = {
            name: 'aym'
        };
        // 向domain2传送跨域数据
        iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com');
    };
 
    // 接受domain2返回数据
    window.addEventListener('message', function(e) {
        alert('data from domain2 ---> ' + e.data);
    }, false);
</script>

2.)b.html:(

<script> // 接收domain1的数据 window.addEventListener('message', function(e) { alert('data from domain1 ---> ' + e.data); var data = JSON.parse(e.data); if (data) { data.number = 16; // 处理后再发回domain1 window.parent.postMessage(JSON.stringify(data), ''); } }, false); </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
    // 接收domain1的数据
    window.addEventListener('message', function(e) {
        alert('data from domain1 ---> ' + e.data);
 
        var data = JSON.parse(e.data);
        if (data) {
            data.number = 16;
 
            // 处理后再发回domain1
            window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');
        }
    }, false);
</script>

<script type=”text/javascript”>
var load = false;
function iLoad() {
if(load == false) {
// 同域处理,请求后会再次重新加载iframe
document.getElementById(‘iframe1′).contentWindow.location = ‘/’;
load = true;
} else {
// 获取window.name的内容,注意必须进行同域处理后方可访问!
var data = document.getElementById(‘iframe1′).contentWindow.name;
alert(data); // {“id”:”3″, “name”:”leisure”}
load = false;
}
}
</script>

主页面的包含的iframe之间相互调用;

 

六、 跨域资源共享(CORS)

普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置。
带cookie请求:前后端都需要设置字段,另外需注意:所带cookie为跨域请求接口所在域的cookie,而非当前页。
目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。

3、定义一个form,设置form的target为iframe的id,然后提交form

 

其实我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景。

1、 前端设置:

1.)原生ajax

// 前端设置是否带cookie xhr.withCredentials = true;

1
2
// 前端设置是否带cookie
xhr.withCredentials = true;

示例代码:

var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容 // 前端设置是否带cookie xhr.withCredentials = true; xhr.open('post', '', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send('user=admin'); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { alert(xhr.responseText); } };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
 
// 前端设置是否带cookie
xhr.withCredentials = true;
 
xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');
 
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        alert(xhr.responseText);
    }
};

2.)jQuery ajax

$.ajax({ ... xhrFields: { withCredentials: true // 前端设置是否带cookie }, crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie ... });

1
2
3
4
5
6
7
8
$.ajax({
    ...
   xhrFields: {
       withCredentials: true    // 前端设置是否带cookie
   },
   crossDomain: true,   // 会让请求头中包含跨域的额外信息,但不会含cookie
    ...
});

3.)vue框架
在vue-resource封装的ajax组件中加入以下代码:

Vue.http.options.credentials = true

1
Vue.http.options.credentials = true

 代码如下

主要知识点

 

2、 服务端设置:

若后端设置成功,前端浏览器控制台则不会出现跨域报错信息,反之,说明没设成功。

1.)Java后台:

/* * 导入包:import javax.servlet.http.HttpServletResponse; * 接口参数中定义:HttpServletResponse response */ response.setHeader("Access-Control-Allow-Origin", ""); // 若有端口需写全(协议+域名+端口) response.setHeader("Access-Control-Allow-Credentials", "true");

1
2
3
4
5
6
/*
* 导入包:import javax.servlet.http.HttpServletResponse;
* 接口参数中定义:HttpServletResponse response
*/
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com");  // 若有端口需写全(协议+域名+端口)
response.setHeader("Access-Control-Allow-Credentials", "true");

2.)Nodejs后台示例:

var http = require('http'); var server = http.createServer(); var qs = require('querystring'); server.on('request', function(req, res) { var postData = ''; // 数据块接收中 req.addListener('data', function(chunk) { postData += chunk; }); // 数据接收完毕 req.addListener('end', function() { postData = qs.parse(postData); // 跨域后台设置 res.writeHead(200, { 'Access-Control-Allow-Credentials': 'true', // 后端允许发送Cookie 'Access-Control-Allow-Origin': '', // 允许访问的域(协议+域名+端口) 'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:脚本无法读取cookie }); res.write(JSON.stringify(postData)); res.end(); }); }); server.listen('8080'); console.log('Server is running at port 8080...');

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var http = require('http');
var server = http.createServer();
var qs = require('querystring');
 
server.on('request', function(req, res) {
    var postData = '';
 
    // 数据块接收中
    req.addListener('data', function(chunk) {
        postData += chunk;
    });
 
    // 数据接收完毕
    req.addListener('end', function() {
        postData = qs.parse(postData);
 
        // 跨域后台设置
        res.writeHead(200, {
            'Access-Control-Allow-Credentials': 'true',     // 后端允许发送Cookie
            'Access-Control-Allow-Origin': 'http://www.domain1.com',    // 允许访问的域(协议+域名+端口)
            'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly'   // HttpOnly:脚本无法读取cookie
        });
 
        res.write(JSON.stringify(postData));
        res.end();
    });
});
 
server.listen('8080');
console.log('Server is running at port 8080...');

复制代码

1:document.getElementById("ii").contentWindow 得到iframe对象后,就可以通过contentWindow得到iframe包含页面的window对象,然后就可以正常访问页面元素了;

什么是同源策略?

七、 nginx代理跨域

<form action=”url” method=”POST” target=”iframe1″>
<button type=”submit” value=”submit” />
</form>

2:$("#ii")[0].contentWindow  如果用jquery选择器获得iframe,需要加一个【0】;

 

1、 nginx配置解决iconfont跨域

浏览器跨域访问js、css、img等常规静态资源被同源策略许可,但iconfont字体文件(eot|otf|ttf|woff|svg)例外,此时可在nginx的静态资源服务器中加入以下配置。

location / { add_header Access-Control-Allow-Origin *; }

1
2
3
location / {
  add_header Access-Control-Allow-Origin *;
}

二、JSONP

3:$("#ii")[0].contentWindow.$("#dd").val() 可以在得到iframe的window对象后接着使用jquery选择器进行页面操作;

同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指”协议+域名+端口”三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

2、 nginx反向代理接口跨域

跨域原理: 同源策略是浏览器的安全策略,不是HTTP协议的一部分。服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题。

实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。

nginx具体配置:

#proxy服务器 server { listen 81; server_name www.domain1.com; location / { proxy_pass ; #反向代理 proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名 index index.html index.htm; # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用 add_header Access-Control-Allow-Origin ; #当前端只跨域不带cookie时,可为* add_header Access-Control-Allow-Credentials true; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#proxy服务器
server {
    listen       81;
    server_name  www.domain1.com;
 
    location / {
        proxy_pass   http://www.domain2.com:8080;  #反向代理
        proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
        index  index.html index.htm;
 
        # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
        add_header Access-Control-Allow-Origin http://www.domain1.com;  #当前端只跨域不带cookie时,可为*
        add_header Access-Control-Allow-Credentials true;
    }
}

1.) 前端代码示例:

var xhr = new XMLHttpRequest(); // 前端开关:浏览器是否读写cookie xhr.withCredentials = true; // 访问nginx中的代理服务器 xhr.open('get', '', true); xhr.send();

1
2
3
4
5
6
7
8
var xhr = new XMLHttpRequest();
 
// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;
 
// 访问nginx中的代理服务器
xhr.open('get', 'http://www.domain1.com:81/?user=admin', true);
xhr.send();

2.) Nodejs后台示例:

var http = require('http'); var server = http.createServer(); var qs = require('querystring'); server.on('request', function(req, res) { var params = qs.parse(req.url.substring(2)); // 向前台写cookie res.writeHead(200, { 'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:脚本无法读取 }); res.write(JSON.stringify(params)); res.end(); }); server.listen('8080'); console.log('Server is running at port 8080...');

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var http = require('http');
var server = http.createServer();
var qs = require('querystring');
 
server.on('request', function(req, res) {
    var params = qs.parse(req.url.substring(2));
 
    // 向前台写cookie
    res.writeHead(200, {
        'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly'   // HttpOnly:脚本无法读取
    });
 
    res.write(JSON.stringify(params));
    res.end();
});
 
server.listen('8080');
console.log('Server is running at port 8080...');

服务器返回

4:$("#ii")[0].contentWindow.hellobaby="dsafdsafsdafsdafsdafsdafsadfsadfsdafsadfdsaffdsaaaaaaaaaaaaa"; 可以通过这种方式向iframe页面传递参数,在iframe页面window.hellobaby就可以获取到值,hellobaby是自定义的变量;

 

八、 Nodejs中间件代理跨域

node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发。

 代码如下

5:在iframe页面通过parent可以获得主页面的window,接着就可以正常访问父亲页面的元素了;

同源策略限制以下几种行为:

1、 非vue框架的跨域(2次跨域)

利用node + express + http-proxy-middleware搭建一个proxy服务器。

1.)前端代码示例:

var xhr = new XMLHttpRequest(); // 前端开关:浏览器是否读写cookie xhr.withCredentials = true; // 访问http-proxy-middleware代理服务器 xhr.open('get', '', true); xhr.send();

1
2
3
4
5
6
7
8
var xhr = new XMLHttpRequest();
 
// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;
 
// 访问http-proxy-middleware代理服务器
xhr.open('get', 'http://www.domain1.com:3000/login?user=admin', true);
xhr.send();

2.)中间件服务器:

var express = require('express'); var proxy = require('http-proxy-middleware'); var app = express(); app.use('/', proxy({ // 代理跨域目标接口 target: '', changeOrigin: true, // 修改响应头信息,实现跨域并允许带cookie onProxyRes: function(proxyRes, req, res) { res.header('Access-Control-Allow-Origin', ''); res.header('Access-Control-Allow-Credentials', 'true'); }, // 修改响应信息中的cookie域名 cookieDomainRewrite: 'www.domain1.com' // 可以为false,表示不修改 })); app.listen(3000); console.log('Proxy server is listen at port 3000...');

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var express = require('express');
var proxy = require('http-proxy-middleware');
var app = express();
 
app.use('/', proxy({
    // 代理跨域目标接口
    target: 'http://www.domain2.com:8080',
    changeOrigin: true,
 
    // 修改响应头信息,实现跨域并允许带cookie
    onProxyRes: function(proxyRes, req, res) {
        res.header('Access-Control-Allow-Origin', 'http://www.domain1.com');
        res.header('Access-Control-Allow-Credentials', 'true');
    },
 
    // 修改响应信息中的cookie域名
    cookieDomainRewrite: 'www.domain1.com'  // 可以为false,表示不修改
}));
 
app.listen(3000);
console.log('Proxy server is listen at port 3000...');

3.)Nodejs后台同(六:nginx)

复制代码

6:parent.$("#ii")[0].contentWindow.ff; 同级iframe页面之间调用,需要先得到父亲的window,然后调用同级的iframe得到window进行操作;

 

2、 vue框架的跨域(1次跨域)

利用node + webpack + webpack-dev-server代理接口跨域。在开发环境下,由于vue渲染服务和接口代理服务都是webpack-dev-server同一个,所以页面与代理接口之间不再跨域,无须设置headers跨域信息了。

webpack.config.js部分配置:

module.exports = { entry: {}, module: {}, ... devServer: { historyApiFallback: true, proxy: [{ context: '/login', target: '', // 代理跨域目标接口 changeOrigin: true, cookieDomainRewrite: 'www.domain1.com' // 可以为false,表示不修改 }], noInfo: true } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
    entry: {},
    module: {},
    ...
    devServer: {
        historyApiFallback: true,
        proxy: [{
            context: '/login',
            target: 'http://www.domain2.com:8080',  // 代理跨域目标接口
            changeOrigin: true,
            cookieDomainRewrite: 'www.domain1.com'  // 可以为false,表示不修改
        }],
        noInfo: true
    }
}

 callback({“id”: “3″, “name”: “leisure”});
<script type=”text/javascript”>
function callback(data) {
alert(data);
}
</script>
<script type=”text/javascript” src=”;

 

1.) Cookie、LocalStorage 和 IndexDB 无法读取

九、 WebSocket协议跨域

WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。
原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。

1.)前端代码:

<div>user input:<input type="text"></div> <script src="./socket.io.js"></script> <script> var socket = io(''); // 连接成功处理 socket.on('connect', function() { // 监听服务端消息 socket.on('message', function(msg) { console.log('data from server: ---> ' + msg); }); // 监听服务端关闭 socket.on('disconnect', function() { console.log('Server socket has closed.'); }); }); document.getElementsByTagName('input')[0].onblur = function() { socket.send(this.value); }; </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div>user input:<input type="text"></div>
<script src="./socket.io.js"></script>
<script>
var socket = io('http://www.domain2.com:8080');
 
// 连接成功处理
socket.on('connect', function() {
    // 监听服务端消息
    socket.on('message', function(msg) {
        console.log('data from server: ---> ' + msg);
    });
 
    // 监听服务端关闭
    socket.on('disconnect', function() {
        console.log('Server socket has closed.');
    });
});
 
document.getElementsByTagName('input')[0].onblur = function() {
    socket.send(this.value);
};
</script>

2.)Nodejs socket后台:

var http = require('http'); var socket = require('socket.io'); // 启http服务 var server = http.createServer(function(req, res) { res.writeHead(200, { 'Content-type': 'text/html' }); res.end(); }); server.listen('8080'); console.log('Server is running at port 8080...'); // 监听socket连接 socket.listen(server).on('connection', function(client) { // 接收信息 client.on('message', function(msg) { client.send('hello:' + msg); console.log('data from client: ---> ' + msg); }); // 断开处理 client.on('disconnect', function() { console.log('Client socket has closed.'); }); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var http = require('http');
var socket = require('socket.io');
 
// 启http服务
var server = http.createServer(function(req, res) {
    res.writeHead(200, {
        'Content-type': 'text/html'
    });
    res.end();
});
 
server.listen('8080');
console.log('Server is running at port 8080...');
 
// 监听socket连接
socket.listen(server).on('connection', function(client) {
    // 接收信息
    client.on('message', function(msg) {
        client.send('hello:' + msg);
        console.log('data from client: ---> ' + msg);
    });
 
    // 断开处理
    client.on('disconnect', function() {
        console.log('Client socket has closed.');
    });
});

3 赞 13 收藏 3 评论

图片 7

源码

2.) DOM 和 Js对象无法获得

PHP页面返回的JSONP格式应该是这样的:

main.html

3.) AJAX 请求不能发送

 代码如下

 代码如下

 

复制代码

复制代码

常见跨域场景

<?php
 echo $_GET["callback"].'
 (
    {
        title: "The Principles of Beautiful Web Design, 2nd Edition",
        url: "",
        author: "Jason Beaird",
        publisher: "SitePoint",
        price: {
            currency: "USD",
            amount: 39.95
         }
 }
 );
 '
?>

?<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" ";
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>显示图表</title>
<script src="/jquery-1.7.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
    var gg="dsafdsafdsafdsafsdaf";
    function ggMM() {
        alert("2222222222222222222222222222222");
    }
    function callIframeMethod() {
        //document.getElementById("ii").contentWindow.test();
        $("#ii")[0].contentWindow.test(); //用jquery调用需要加一个[0]
    }
    function callIframeField() {
        alert($("#ii")[0].contentWindow.ff);
    }
    function callIframeHtml() {
        alert($("#ii")[0].contentWindow.$("#dd").val());
        //alert($("#ii")[0].contentWindow.document.getElementById("dd").value);
        //alert($("#ii")[0].contentWindow.document.getElementById("dd").value);             
    }   
    function giveParameter() {
        $("#ii")[0].contentWindow.hellobaby="dsafdsafsdafsdafsdafsdafsadfsadfsdafsadfdsaffdsaaaaaaaaaaaaa";
    }
</script>
</head>
<body>
    <a href="#" onClick="giveParameter();">参数传递</a>
    <a href="#" onClick="callIframeMethod();">调用子iframe方法</a>
    <a href="#" onClick="callIframeField();">调用子iframe变量</a>
    <a href="#" onClick="callIframeHtml();">调用子iframe组件</a></br>  
    <iframe id="ii" src="frame.htm" width="100%" frameborder="0"></iframe>
    <iframe id="new" src="newFrame.htm" width="100%" frameborder="0"></iframe>
</body>
</html>

 

而静态HTML发起请求的代码可以参考下面:

frame.htm

URL                                      说明                    是否允许通信

         同一域名,不同文件或路径           允许

 

         同一域名,不同端口                不允许

 

        同一域名,不同协议                不允许

 

           域名和域名对应相同ip              不允许

 

           主域相同,子域不同                不允许

 

        不同域名                         不允许

 代码如下

 代码如下

 

复制代码

复制代码

跨域解决方案

<script language="javascript" src="你的网址/zt/access_count/js/jquery-1.4.2.min.js"></script>
<script language="javascript" src="你的网址/zt/access_count/js/jquery.jsonp-2.1.4.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
 insert_vote();
})

?<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" ";
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>显示图表</title>
<script src="scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
 
var ff="adfdasfdsafdsafdsaf";
function test() {
    alert($("#dd").val());
}
function callMainField() {
    alert(parent.gg);
}
function callMainMethod() {
    parent.ggMM();
}
function callMainHtml() {
    alert(parent.$("#ii").attr("id"));
}
function getParameter() {
    alert(window.hellobaby);
}
</script>
</head>
<body>
    <a href="#" onClick="getParameter();">接受参数</a>
    <a href="#" onClick="callMainMethod();">调用子iframe方法</a>
    <a href="#" onClick="callMainField();">调用主窗口变量</a>
    <a href="#" onClick="callMainHtml();">调用子iframe组件</a>   
    <input id="dd" type="text" value="1111111111"/>
</body>
</html>  

 

function insert_vote(){
 var j = null;
 $.ajax({
  type:'get',
  url:'你的网址/zt/access_count/jsonp.php',
  dataType:'jsonp',
  jsonp:"callback",
  data:{"a":"insert", "type":"aa", "time":"bb", "id":"dd", "allowVote":"cc"},
  async: false,
  success:function(data){
   j = data;
   //alert("1");
   alert(j.title);
  }
 }) 
}
 
function init(){
 $.ajax({
    dataType: 'jsonp',
    data: 'id=10',
    jsonp: 'jsonp_callback',
    url: '你的网址/zt/access_count/jsonp.php',
    success: function ()
     {
      // do stuff
   alert(jsonp.respond);
    },
 });
}

兄弟iframe页面 newIframe.htm

1、 通过jsonp跨域

function init2(){
 $.ajax({   
  async:false,   
   url: '你的网址/zt/access_count/jsonp.php',  // 跨域URL  
     type: 'GET',   
      dataType: 'jsonp',   
     jsonp: 'jsoncallback', //默认callback  
     data: 'id=10', //请求数据  
      timeout: 5000,   
     beforeSend: function(){ 
   //jsonp 方式此方法不被触发。原因可能是dataType如果指定为jsonp的话,就已经不是ajax事件了  
      },  
     success: function(json) {
   //客户端jquery预先定义好的callback函数,成功获取跨域服务器上的json数据后,会动态执行这个callback函数
   alert(json.respond.title);   
       if(json.actionErrors.length!=0)
   {   
          alert(json.actionErrors);   
         }   
  },   
  complete: function(XMLHttpRequest, textStatus){   
                
  },   
  error: function(xhr){   
               //jsonp 方式此方法不被触发  
               //请求出错处理   
   alert("请求出错(请检查相关度网络状况.)");   
  }   
 }); 
}
</script>

 代码如下

2、 document.domain + iframe跨域

通用方法:

复制代码

3、 location.hash + iframe

 代码如下

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" ";
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>显示图表</title>
<script src="/jquery-1.7.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
function callLevelFrame() {
    var ff=parent.$("#ii")[0].contentWindow.ff;
    alert(ff);
}
</script>
</head>
<body>
    <a href="#" onClick="callLevelFrame();">调用兄弟iframe</a>   
    <input id="nn" type="text" value="sdafsdfsa"/>
</body>
</html>

4、 window.name + iframe跨域

复制代码

其实这个问题可以被大大的简化,框架应用中有一个固定不变的窗口叫window.top,如果我们把数据缓存到这个页面,其下所有框架都可以获取到,无论子页面如何变幻。不需要采用Cookie,也不需要采用什么HTML5本地数据库策略,你只需要每个页面引用一个js文件,内容如下:

5、 postMessage跨域

 // 初始化数据,同一个cookie一分钟的访问量都算一次
 function init_count(pageType, id){
  var j = null;
  $.ajax({ 
         type: "get",  //使用get方法访问后台 
         dataType: "jsonp", //返回json格式的数据 
   jsonp:"callback",
         url: "", //要访问的后台地址 
   data:{"opp":"main", "pageType":pageType, "id":id},
   async: false,
         success: function(data){ 
          //alert(data.total);
    //$('#pc_1').html(msg.total);
    $.each(data, function(i, v){
     var tmp = v.record.split(":");
     var month_view = tmp[tmp.length - 1];
     $("label[id=pc_"+v.page_id+"]").html(v.total);
     $("label[id=pcm_"+v.page_id+"]").html(v.week);
    }) 
         } 
     }) 
 }

 代码如下

6、 跨域资源共享(CORS)

三、jQuery.getJSON

复制代码

7、 nginx代理跨域

JSON是一个轻量级的数据交换格式。JSON对于JavaScript开发人员充满魅力的原因在于JSON本身就是Javascript中的对象

 
var share = {

8、 nodejs中间件代理跨域

首先我们来定义接口的规范,就像这样:

 /**
  * 跨框架数据共享接口
  * @param {String} 存储的数据名
  * @param {Any}  将要存储的任意数据(无此项则返回被查询的数据)
  */
 data: function (name, value) {
  var top = window.top,
   cache = top['_CACHE'] || {};
  top['_CACHE'] = cache;
  
  return value !== undefined ? cache[name] = value : cache[name];
 },
 
 /**
  * 数据共享删除接口
  * @param {String} 删除的数据名
  */
 removeData: function (name) {
  var cache = window.top['_CACHE'];
  if (cache && cache[name]) delete cache[name];
 }
 
};

9、 WebSocket协议跨域

 

 

symbol是请求条件,callback是回调函数名称。

这个寥寥数行的方法可以共享任意类型的数据供各个框架页面读取,它与页面名称、层级毫无关系,就算哪天框架页面层级被修改,你也完全不用担心,它可正常工作。

一、 通过jsonp跨域

在页面文件中,我们使用JQuery的支持:

例如,如我们可以在A页面存入共享数据:

 

服务器返回 json格式数据 test({“id”: “3″, “name”: “leisure”});

 代码如下

通常为了减轻web服务器的负载,我们把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。

test函数名为callback参数中定义

复制代码

 

 代码如下

share.data(‘myblog’, ‘);
share.data(‘editTitle’, function (val) {
document.title = val;
});

1.)原生实现:

复制代码

然后某框架页面任意取A页面的数据

 

$.getJSON(url + “?callback=?”, data, function(data) {
}

 代码如下

<script>

    var script = document.createElement('script');

    script.type = 'text/javascript';

 

    // 传参并指定回调执行函数为onBack

    script.src = '';

    document.head.appendChild(script);

 

    // 回调执行函数

    function onBack(res) {

        alert(JSON.stringify(res));

    }

</script>

复制代码

 

 代码如下

alert(‘我的博客地址是: ‘ + share.data(‘myblog’);
var editTitle = share.data(‘editTitle’);
editTitle(‘我已经获取到了数据’);

服务端返回如下(返回时即执行全局函数):

复制代码

实例夸域操作

 

本文由必威发布于必威-前端,转载请注明出处:复制代码,什么是跨域

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。