jsonp

365 阅读5分钟

Json with Padding只是是解决跨域问题而提出的一种方案。 由于同源策略的限制,XMLHttpRequest只允许请求前源(域名、协议、端口)的资源,为了实现跨域请求,可以通过script标签实现跨域请求,然后再服务端输出JSON数据并执行回调函数,从而解决跨域数据请求

通信原理:首先在客户端注册一个callback,然后把callback的名字传给服务器。此时,服务器先生成json数据,然后以javascript语法的方式,生成function,function名字就是传递上来I带参数jsonp。最后将json数据直接以入参的方式,放置function中,这样就生成js语法的文档,返回给客户端。客户端浏览器,解析script变迁,并执行返回javascript文档,此时数据作为参数,传入了客户端预先定义好的callback函数里。简单的说,就是利用script标签没有跨域限制的“漏洞”来达到与第三方通讯的目的。

jsonp 是一种数据调用的方式,带callback的json就是jsonp

jsonp弊端:需要服务端改动参数;只支持get请求;发送的不是xhr请求;

例: jsonp


 1. $.ajax({
                type: "get",
                async: false,
                url: " ",
                dataType: "jsonp",
                jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
                jsonpCallback: "localHandler",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
                success: function (json) {
                    $('body').append('<h2>您查询到航班信息:票价: ' + json.price + ' 元,余票: ' + json.tickets + ' 张。</h2>');
                },
                error: function () {
                    alert('fail');
                }
            });
            
            
json.php
            
header('Content-Type:application/json; charset=utf-8');
$callback='localHandler';
$data=array(
    'price'=>26358,
    'tickets'=>56
);
echo $callback.'('.json_encode($data).');';


2.<script type="text/javascript" src="Service.ashx?callback=jsonpCallback" />
//回调函数function jsonpCallback(content){ alert(content); } </script>
运行的结果显示test jsonp,可以看出整个过程:
~~~~~~~jsonpCallback的回调函数和ajax中的success中的成功回调都可以操作返回的数据


3.用jQuery中提供的$.getJson方法来跨域访问。getJson有3个参数:
I.   url:请求地址;
II.  data:发送到服务端的参数;
III. callback:成功时的回调函数。

PS:getJson的使用方法和普通的$.get方法基本一致,不同的地方在于getJson需要在url后面的参数部分加上callback=?这一固定部分,jQuery 将自动替换 ? 为正确的函数名,以执行回调函数。然后在回调函数中操作从异域返回的json对象,回调函数callback的参数即为该json对象。

 $.getJSON("GetAllNames?callback=?", function(json) {
      for (var i = 0; i < json.length; i++) {
        $("#nameList").append("<li>" + json[i] + "</li>");
      }
    });
    
** 服务端编写
服务端的逻辑主要是将数据序列化为json字符串,然后封装成"callback(json)"的形式,callback为jQuery自动生成并传到服务端的函数名称。下面使用C#实现:

public class UserController :controller
{
    public string GetAllNames(string callback)
  {
    string[]names = new string[] { "1", "2222", "333", "3",  };
    JavaScriptSerializer jss = new JavaScriptSerializer();
    string json = jss.Serialize(names);
    return string.Format("{0}({1})", callback, json);
  }
}


思考:如果服务端已经写死了callback(如:return string.Format("moty({0})", json);),那么客户端该怎么写呢?

$.ajax("User/GetAllNames", {
  jsonpCallback: "moty",
  dataType: "jsonp",
  success: function(json) {
    for (var i = 0; i < json.length; i++) {
      $("#nameList").append("<li>" + json[i] + "</li>");
    }
  }
});

 

jsonp实现input搜索内容--返回后端数据

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>JSONP</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            list-style: none;
        }

        #wrap {
            width: 500px;
            margin: 100px auto 0;
        }

        #wrap input {
            width: 486px;
            height: 40px;
            padding-left: 10px;
        }

        #list {
            margin-top: 10px;
            background: #333;
        }

        #list li {
            width: 490px;
            line-height: 40px;
            background: #ccc;
            padding-left: 10px;
            margin-bottom: 3px;
        }
    </style>
</head>

<body>
    <div id="wrap">
        <input type="text" placeholder="请输入内容" id="ipt">
        <ul id="list">
        </ul>
    </div>
    <script>
        var ipt = document.getElementById('ipt'),
            list = document.getElementById('list');
        var Script = null;
        ipt.onkeyup = function () {
            if (Script) {
                document.body.removeChild(Script);//清除多次创建script标签
            }
            Script = document.createElement('script');
            Script.src = 'suggestion.baidu.com/su?wd=' + ipt.value + '&cb=mycallbacks&t=' + new Date().getTime();
            document.body.appendChild(Script);
        }
        function mycallbacks(json) {  mycallbacks是回调后端动态创建的函数(此函数名可自定义)
            list.innerHTML = '';
            for (var i = 0; i < json.s.length; i++) {
                list.innerHTML += '<li>' + json.s[i] + '</li>';
            }
            console.log(json);
        }
    </script>
</body>

</html>

 

用h5的postMessage做跨域:

window.postMessage()方法安全地启用Window对象之间的跨源通信;例如,在页面和它产生的弹出窗口之间,或者在页面和嵌入其中的iframe之间。
postMessage()方法语法
targetWindow .postMessage(message,targetOrigin,[ transfer ]);
targetWindow
对将接收消息的窗口的引用。获得此类引用的方法包括:
Window.open (生成一个新窗口然后引用它),
Window.opener (引用产生这个的窗口),
HTMLIFrameElement.contentWindow(<iframe>从其父窗口引用嵌入式),
Window.parent(从嵌入式内部引用父窗口<iframe>)
Window.frames +索引值(命名或数字)。
message
要发送到其他窗口的数据。使用结构化克隆算法序列化数据。这意味着您可以将各种各样的数据对象安全地传递到目标窗口,而无需自己序列化。
targetOrigin
指定要调度的事件的targetWindow的原点,可以是文字字符串"*"(表示没有首选项),也可以是URI。如果在计划调度事件时,targetWindow文档的方案,主机名或端口与targetOrigin提供的内容不匹配,则不会调度该事件;只有当所有的三个条件都匹配时,将调度该事件。该机制可以控制发送消息的位置;例如,如果postMessage()用于传输密码,则该参数必须是URI,其来源与包含密码的消息的预期接收者相同,以防止恶意第三方拦截密码。始终提供具体的targetOrigin,而不是*,如果您知道其他窗口的文档应该位于何处。未能提供特定目标会泄露您发送给任何感兴趣的恶意站点的数据。
transfer(可选的)
是与消息一起传输的Transferable对象序列。这些对象的所有权将提供给目标端,并且它们在发送端不再可用。 


例:
a页面向b页面传值
a.html:
    window.top.postMessage('ooop','a.html')
b.html
    <iframe src="a.html"></iframe>
    window.addEventListener('message',function (e) {
        if (e.orgin === 'a.html') 
        console.log(e.data) //用于接收消息的任何事件侦听器必须首先使用origin和可能的source属性检查消息发送者的身份。
    })
    

postMessage跨域