JS跨域:window.postMessage + window.name +jsonp

1.window.postMessage

(1)在发送数据窗口执行:otherWindow.postMessage(msg,targetOrigin)

  • otherWindow:表示接受数据的窗口的window对象,包括iframe的contentWindwohe和通过window.open打开的新窗口。
  • msg表示要发送的数据,包扩字符串和对象(ie9以下不支持,可以利用字符串和json互换)
  • origin表示接收的域名。
(2)在接受的窗口监听window的message事件,回掉函数参数接受一个事件对象event,包括的属性有:

  • data:接受的数据
  • origin:发送端的域
  • source:发送端的DOMWindow对象
  • 例子
  • 1.在父框架页面index.html发送obj对象给远程服务器的wozien.com/test/b.html,该页面是通过iframe加载的,如下
  • [html]  view plain  copy
    1. <!DOCTYPE html>  
    2. <html>  
    3. <head>  
    4.     <title>window.postMessage</title>  
    5.       
    6. </head>  
    7. <body>  
    8.     <iframe id="proxy" src="http://wozien.com/test/b.html" onload = "postMsg()" style="display: none" ></iframe>  
    9.   
    10.     <script type="text/javascript">  
    11.         var obj = {  
    12.             msg: 'this is come from client message!'  
    13.         }  
    14.   
    15.         function postMsg (){  
    16.             var iframe = document.getElementById('proxy');  
    17.             var win = iframe.contentWindow;  
    18.             win.postMessage(obj,'http://wozien.com');  
    19.         }  
    20.           
    21.     </script>  
    22. </body>  
    23. </html>  
    2.在远程页面b.html中监听message事件,先通过origin属性判断下数据来源的域是否可信任,加强安全措施。具体代码如下:
    [html]  view plain  copy
    1. <!DOCTYPE html>  
    2. <html>  
    3. <head>  
    4.     <title></title>  
    5.     <script type="text/javascript">  
    6.         window.onmessage = function(e){  
    7.             if(e.origin !== 'http://localhost') return;  
    8.             console.log(e.origin+' '+e.data.msg);  
    9.         }  
    10.     </script>  
    11. </head>  
    12. <body>  
    13.     <p>this is my server</p>  
    14. </body>  
    15. </html>  

2.window.name

有三个页面:

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

实现起来基本步骤如下:

    在应用页面(a.com/app.html)中创建一个iframe,把其src指向数据页面(b.com/data.html)。
    数据页面会把数据附加到这个iframe的window.name上,data.html代码如下:

?
1
2
3
4
<script type= "text/javascript" >
   window.name = 'I was there!' // 这里是要传输的数据,大小一般为2M,IE和firefox下可以大至32M左右
                    // 数据格式可以自定义,如json、字符串
</script>

    在应用页面(a.com/app.html)中监听iframe的onload事件,在此事件中设置这个iframe的src指向本地域的代理文件(代理文件和应用页面在同一域下,所以可以相互通信)。app.html部分代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script type= "text/javascript" >
     var state = 0,
     iframe = document.createElement( 'iframe' ),
     loadfn = function () {
       if (state === 1) {
         var data = iframe.contentWindow.name;  // 读取数据
         alert(data);  //弹出'I was there!'
       } else if (state === 0) {
         state = 1;
         iframe.contentWindow.location = "http://a.com/proxy.html" ;  // 设置的代理文件
       }
     };
     iframe.src = 'http://b.com/data.html' ;
     if (iframe.attachEvent) {
       iframe.attachEvent( 'onload' , loadfn);
     } else {
       iframe.onload = loadfn;
     }
     document.body.appendChild(iframe);
   </script>

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

?
1
2
3
4
5
<script type= "text/javascript" >
     iframe.contentWindow.document.write( '' );
     iframe.contentWindow.close();
     document.body.removeChild(iframe);
   </script>

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

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

实现起来基本步骤如下:

    在应用页面(a.com/app.html)中创建一个iframe,把其src指向数据页面(b.com/data.html)。
    数据页面会把数据附加到这个iframe的window.name上,data.html代码如下:

?
1
2
3
4
<script type= "text/javascript" >
   window.name = 'I was there!' // 这里是要传输的数据,大小一般为2M,IE和firefox下可以大至32M左右
                    // 数据格式可以自定义,如json、字符串
</script>

    在应用页面(a.com/app.html)中监听iframe的onload事件,在此事件中设置这个iframe的src指向本地域的代理文件(代理文件和应用页面在同一域下,所以可以相互通信)。app.html部分代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script type= "text/javascript" >
     var state = 0,
     iframe = document.createElement( 'iframe' ),
     loadfn = function () {
       if (state === 1) {
         var data = iframe.contentWindow.name;  // 读取数据
         alert(data);  //弹出'I was there!'
       } else if (state === 0) {
         state = 1;
         iframe.contentWindow.location = "http://a.com/proxy.html" ;  // 设置的代理文件
       }
     };
     iframe.src = 'http://b.com/data.html' ;
     if (iframe.attachEvent) {
       iframe.attachEvent( 'onload' , loadfn);
     } else {
       iframe.onload = loadfn;
     }
     document.body.appendChild(iframe);
   </script>

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

?
1
2
3
4
5
<script type= "text/javascript" >
     iframe.contentWindow.document.write( '' );
     iframe.contentWindow.close();
     document.body.removeChild(iframe);
   </script>

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

3.jsonp

JSONP具体实现

1.首先看下ajax中如果进行跨域请求会如何。 
前端代码在域www.practice.com下面,使用ajax发送了一个跨域的get请求

<!DOCTYPE html>
<html>
<head> <title>GoJSONP</title> </head> <body> <script type="text/javascript"> function jsonhandle(data){ alert("age:" + data.age + "name:" + data.name); } </script> <script type="text/javascript" src="jquery-1.8.3.min.js"> </script> <script type="text/javascript"> $(document).ready(function(){ $.ajax({ type : "get", async: false, url : "http://www.practice-zhao.com/student.php?id=1", type: "json", success : function(data) { jsonhandle(data); } }); }); </script> </body> </html>

后端PHP代码放在域www.practice-zhao.com下,简单的输出一段json格式的数据

jsonhandle({
    "age" : 15, "name": "John", })

当访问前端代码http://www.practice.com/gojsonp/index.html 时 chrome报以下错误 
这里写图片描述
提示了不同源的URL禁止访问

2.下面使用JSONP,将前端代码中的ajax请求去掉,添加了一个script标签,标签的src指向了另一个域www.practice-zhao.com下的remote.js脚本

<!DOCTYPE html>
<html>
<head> <title>GoJSONP</title> </head> <body> <script type="text/javascript"> function jsonhandle(data){ alert("age:" + data.age + "name:" + data.name); } </script> <script type="text/javascript" src="jquery-1.8.3.min.js"> </script> <script type="text/javascript" src="http://www.practice-zhao.com/remote.js"></script> </body> </html>

这里调用了跨域的remote.js脚本,remote.js代码如下:

jsonhandle({
    "age" : 15, "name": "John", })

也就是这段远程的js代码执行了上面定义的函数,弹出了提示框 
这里写图片描述

3.将前端代码再进行修改,代码如下:

<!DOCTYPE html>
<html>
<head> <title>GoJSONP</title> </head> <body> <script type="text/javascript"> function jsonhandle(data){ alert("age:" + data.age + "name:" + data.name); } </script> <script type="text/javascript" src="jquery-1.8.3.min.js"> </script> <script type="text/javascript"> $(document).ready(function(){ var url = "http://www.practice-zhao.com/student.php?id=1&callback=jsonhandle"; var obj = $('<script><\/script>'); obj.attr("src",url); $("body").append(obj); }); </script> </body> </html>

这里动态的添加了一个script标签,src指向跨域的一个php脚本,并且将上面的js函数名作为callback参数传入,那么我们看下PHP代码怎么写的:

<?php
$data = array(
    'age' => 20, 'name' => '张三', ); $callback = $_GET['callback']; echo $callback."(".json_encode($data).")"; return;

PHP代码返回了一段JS语句,即

jsonhandle({
    "age" : 15, "name": "张三", })

此时访问页面时,动态添加了一个script标签,src指向PHP脚本,执行返回的JS代码,成功弹出提示框。 
所以JSONP将访问跨域请求变成了执行远程JS代码,服务端不再返回JSON格式的数据,而是返回了一段将JSON数据作为传入参数的函数执行代码。

4.最后jQuery提供了方便使用JSONP的方式,代码如下:

<!DOCTYPE html>
<html>
<head> <title>GoJSONP</title> </head> <body> <script type="text/javascript" src="jquery-1.8.3.min.js"> </script> <script type="text/javascript"> $(document).ready(function(){ $.ajax({ type : "get", async: false, url : "http://www.practice-zhao.com/student.php?id=1", dataType: "jsonp", jsonp:"callback", //请求php的参数名 jsonpCallback: "jsonhandle",//要执行的回调函数 success : function(data) { alert("age:" + data.age + "name:" + data.name); } }); }); </script> </body> </html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值