欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JSONP基础知识详解

程序员文章站 2022-04-26 17:39:12
前面的话 jsonp是json with padding(填充式json或参数式json)的简写,是应用json的一种新方法,常用于务器与客户端跨源通信,在后来的web服...

前面的话

jsonp是json with padding(填充式json或参数式json)的简写,是应用json的一种新方法,常用于务器与客户端跨源通信,在后来的web服务中非常流行。本文将详细介绍jsonp

基础

jsonp的基本思想是,网页通过添加一个<script>元素,向服务器请求json数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来

当通过<script>元素调用数据时,响应内容必须用javascript函数名和圆括号包裹起来。而不是发送这样一段json数据,这就是jsonp中p的意义所在

[1, 2, {"buckle": "my shoe"}]

jsonp看起来与json差不多,只不过是被包含在函数调用中的json,它会发送这样一个包裹后的json响应:

handleresponse([l, 2, {"buckle": "my shoe"}])

包裹后的响应会成为<script>元素的内容,它先判断json编码后的数据,然后把它传递给handleresponse()函数

在实践中,支持jsonp的服务不会强制指定客户端必须实现的回调函数名称,比如handleresponse。相反,它们使用査询参数的值,允许客户端指定一个函数名,然后使用函数名去填充响应。许多支持jsonp的服务都能分辨出这个参数名。另一个常见的参数名称是callback,为了让使用到的服务支持类似特殊的需求,就需要在代码上做一些修改了

jsonp由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的json数据

http://freegeoip.net/json/?callback=handleresponse

这个url是在请求一个jsonp地理定位服务。通过査询字符串来指定jsonp服务的回调参数是很常见的,就像上面的url所示,这里指定的回调函数的名字叫handleresponse()

jsonp是通过动态<script>元素来使用的,使用时可以为src属性指定一个跨域url。这里的<script>元素与<img>元素类似,都有能力不受限制地从其他域加载资源。因为jsonp是有效的javascript代码,所以在请求完成后,即在jsonp响应加载到页面中以后,就会立即执行

function handleresponse(response){
  alert ("you're at ip address " + response.ip + ", which is in " + response.city + ", "+ response.region_name);
}
var script = document.createelement("script");
script.src = "http://freegeoip.net/json/?callback=handleresponse"; document.body.insertbefore(script, document.body.firstchild);

jsonp之所以在开发人员中极为流行,主要原因是它非常简单易用,老式浏览器全部支持,服务器改造非常小。与图像ping相比,它的优点在于能够直接访问响应文本,支持在浏览器与服务器之间双向通信

使用<script>元素进行ajax传输,不受同源策略的影响,因此可以使用它们从其他的服务器请求数据;而且,包含json编码数据的响应体会自动解码(即执行)

不过,jsonp也有两点不足:首先,jsonp是从其他域中加载代码执行。如果其他域不安全,很可能会在响应中夹带一些恶意代码,而此时除了完全放弃jsonp调用之外,没有办法追究。因此在使用不是自己运维的web服务时,一定得保证它安全可靠;其次,要确定jsonp请求是否失败并不容易。虽然html5给<script>元素新增了一个onerror事件处理程序,但目前还没有得到任何浏览器支持。为此,开发人员不得不使用计时器检测指定时间内是否接收到了响应。但就算这样也不能尽如人意,毕竟不是每个用户上网的速度和带宽都一样

简易示例

【前端】

<button id="btn">获取信息</button>
<img id="img" height="16" style="display:none" src="data:image/gif;base64,r0lgodlhiaagalmaap///7ozs/v7+9bw1uhh4fly8rq6uogbgtq0naebarsbg8texjexl/39/vruvaaaach/c05fvfndqvbfmi4waweaaaah+qqfbqaaacwaaaaaiaagaaae5xdissllrornp0pknrcdfhxvoljlejquosgopsyt4rownssvyw1ica16k8mmmrkcbjskbtfdazyuaekqcfxiq2hgqrfvaqeeijnxvdw6xne4yagrjubcwe60smqudnd4rz1zaqznfagdd0hihh12cee9kjaevlycxig7basmb6slnj87paqbskikoqusnbmdmdc2txqlkuhziytywtxify6be8wjt5yevpjivxnagmlht0vnoggyf0dzxs7apdpb309rnhog5gdqxgldac457d1zz/v/nmom82xihqjykhkp1ozmaddeaaah+qqfbqaaacwaaaaagaaxaaaechdisaskneujfkohs4muyljikmjiv54soypsa0wmlsnqotetbw52mg0ajhypbxioeqrny8v0qfznw+ggwljki4lbqx1ibgjmkrighwjrzcdti2/gh7d9qn774wqgayoefwcchiv/gymdho+qkzktr3p7eqah+qqfbqaaacwbaaaahqaoaaaechdiswdanesnhhjzwe2duseo5sjkkb2hokgyfld1cb/dneoilkti2plyukgeatmbaaacsygbedyd4zn1yiemh0scqqgyehnmtnnaksqjxmbuueypi9ecau/ufnnzeup9vbqebofolmfxwhnoqw6rweoceqah+qqfbqaaacwhaaaagqaraaaeardicdzznovndsvfbhbddpwzgohbge3nqaki0ayejeqogmqdlkenazbujhra0cobyhlvskm4saaawkahcfawtu0a4rxzfwjnzxfwjjwb9ptihru5dvghl+/7nqmbggo/fykhcx8aiameeqah+qqfbqaaacwoaaaaegayaaaezxcwaaq9odamdouai17mcydhwa3mcypb1rooxbktmsbt944bu6zcqcbqiwpb4jaihick86irtb20qvwp7xq/fyv4tnwnz4oqwoeigl0hx/eqsli69bociktke2vvdap5d1p0cw4rach5baufaaaala4aaaasab4aaasakbgcqr3ybimxvkeimsxxhcffpizqbatxisbclibgand+ijygq2i4haamwxbgnhj8bebzgpnnjz7lwpnfdlvglgjmdnw/5drcrhae3xbkm6fqwot1xdnpwcvcjgcjmgeiecyocqlrf4ymbiojvv2ccxzvcoohbwgrcaikcmfujheaifkebquaaaasdwababeahwaabhsqyakgorivelinnoflbjem1bcifbdcbmutkqdtn0cujru5njqrymh5vifttkjcoj2hqjqrheqvqguu+uw6awgewxkoo55lxiihodjky8pbothpxmpayi+hkzoeewktdhkzghmidcoihiuhfbmojxinlr4kcw1odalxsxeaifkebquaaaascaaoabgaegaabgwqyekrcdgbyvvmoof5ilanaiogkroch9hacd3mfmhubzmhibtgwjmbfoldb4goggbcackrcaauwamzowjqexysqsjgwj0kqvkaltiyphp1lbfttp10is6mt5gdvfx1brn8ftsvcaqdob9+kheaifkebquaaaasagasab0adgaabhgqyemrbeps4bqdqzbdr5ichmwegufqgwkakbwwwsihc4lonsxhbscsqoosscgqdjiwwohqnaxwbiyjnxeofciewdi9jczesey7gwmm5doeww4jjoypqq743u1wctv0cgfzbhj5xclfhyd/ewznhoyvdgiofhkqnreaifkebquaaaasaaapabkaeqaabgeqquqrudjrw3vaycz5x2ie6ekckaootasi7ytntq046bbsnctvitz4aotmwkzbic6h6cvajacct0cubtgatg5ntcu9gkidempjg5ybbopwlnvzlwtqyknzagzwahomb2m3ggshsrsrach5baufaaaalaeacaarabgaaarcmkr0gl34npkuyycacamyhbijkgi2uw02vhft33iu7yididad4/ereygdlu/nubaoj9dvc2ecdgfayiuaxs3bboh6mic5iap5eh5fk2exc4tpgwzyiyfgvhembbeaifkebquaaaasaaacaa4ahqaabhmqyanyovislfdgxbj808ep5krwv8qeg+prcoeoiokmwjk0ekcu54h9aoghkgximzgaapqzcccu2ax2o6nuud2pmjcyha4l0udm/ljydcngfgakjqe5yh0wubybauyfbifkhwabgxkdgx5lgxphaxcpbisrads=" alt="loading">
<div id="result"></div>
<script>
var add = (function(){
  var counter = 0;
  return function(){
    return ++counter;
  }
})();
function loadscript(url){
  loadscript.mark = 'load';
  var script = document.createelement("script");
  script.type = "text/javascript";
  script.src = url;
  script.onload = function(){
    img.style.display = 'none';
    btn.removeattribute('disabled');
  }
  document.body.appendchild(script);
}
function test(data){
  var sum = add() - 1;
  if(sum < data.length ){
   result.innerhtml += data[sum];  
  }
}
btn.onclick = function(){
  img.style.display = 'inline-block';
  btn.setattribute('disabled','');
  loadscript('https://www.webhuochai.com/test/getdata.php?callback=test');
}
</script>

【后端】

<?php
function test_input($data) {
  $data = trim($data);
  $data = stripslashes($data);
  $data = htmlspecialchars($data);
  return $data;
}
$arr = [1,2,3,4,5];
echo test_input($_get['callback']) ."(" .json_encode($arr) .");";
?>

百度搜索框

百度搜索框就是使用了jsonp的技术,在百度搜索的url中,有用的查询如下

https://sp0.baidu.com/5a1fazu8aa54nxgko9wtanf6hhy/su?wd=123&&cb=a

结果为:

a({q:"123",p:false,s:["12306","12306铁路客户服务中心","12308汽车订票官网","12306火车票网上订票官网","12333","12315","12345","12333社保查询网","123网址之家","12366"]});

所以,wd为关键词,cb用来jsonp的函数名。在获取的数据中,s为以关键词开始的数据组成的数据

百度搜索的关键url如下

wd为关键词,当wd=a时,将打开关键词为a的网页

<style>
body{margin: 0;}
ul{margin: 0;padding: 0;list-style: none;}
a{color:inherit;text-decoration: none;}
input{padding: 0;border: 0;}
.box{width: 340px;height: 38px;border: 2px solid gray;}
.con{overflow: hidden;}
.input{float: left;width: 300px;height: 38px;}
.search{width: 38px;height: 38px;float: right;background: url('http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/search.png') 0 -38px;}
.list{position: absolute;width: 298px;border: 1px solid #e6e8e9; overflow: hidden;}
.in{line-height: 30px;border-bottom: 1px solid lightblue;cursor:pointer;text-indent: 1em;}
.list .in:last-child{margin-bottom: -1px;}
.in:hover{background-color: #f9f9f9;}
</style>
<div class="box" id="box">
  <div class="con">
    <input class="input" id="search">
    <a target="_blank" id="btn" href="javascript:;" rel="external nofollow" class="search"></a>
  </div>
  <ul class="list" id="list"></ul>    
</div> 
<script>
function loadscript(url){
  loadscript.mark = 'load';
  var script = document.createelement("script");
  script.type = "text/javascript";
  script.src = url;
  document.body.appendchild(script);
}
function callback(data){
  if(data){
    var arr = data.s;
    var html = '';
    for(var i = 0,len = arr.length; i < len; i++){
      html+= "<li class='in'><a href='https://www.baidu.com/s?wd="+ arr[i]+"' target='_blank' style='display:block'>" + arr[i]+ "</a></li>"
    }
    list.innerhtml = html;    
  }
}
search.onkeyup = function(e){
  e = e || event;
  if(e.keycode == '13'){
    window.open('https://www.baidu.com/s?wd=' + this.value);
  }
  if(this.value){
    if(search.data != this.value){
      btn.setattribute('href','https://www.baidu.com/s?wd=' + this.value);
      var that = this;
      loadscript("https://sp0.baidu.com/5a1fazu8aa54nxgko9wtanf6hhy/su?wd=" + that.value + "&&cb=callback");
    }
  }else{
    list.innerhtml = '';
  }
  search.data = this.value;
}
search.onclick = function(e){
  e = e || event;
  list.style.display = 'block';
  if(e.stoppropagation){
    e.stoppropagation();
  }else{
    e.cancelbubble = true;
  }
}
document.onclick = function(){
   list.style.display = 'none';
}
</script>

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!