JSONP基础知识详解


Posted in Javascript onMarch 19, 2017

前面的话

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。相反,它们使用?搜?问?闹担?市砜突Ф酥付ㄒ桓龊????缓笫褂煤???ヌ畛湎煊ΑP矶嘀С?SONP的服务都能分辨出这个参数名。另一个常见的参数名称是callback,为了让使用到的服务支持类似特殊的需求,就需要在代码上做一些修改了

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

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

这个URL是在请求一个JSONP地理定位服务。通过?搜?址??粗付?SONP服务的回调参数是很常见的,就像上面的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,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" 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如下

https://www.baidu.com/s?wd=a

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>

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

Javascript 相关文章推荐
javascript动画对象支持加速、减速、缓入、缓出的实现代码
Sep 30 Javascript
自己写了一个展开和收起的多更能型的js效果
Mar 05 Javascript
用js来刷新当前页面保留参数的具体实现
Dec 23 Javascript
javascript实现获取cookie过期时间的变通方法
Aug 14 Javascript
Javascript节点关系实例分析
May 15 Javascript
canvas快速绘制圆形、三角形、矩形、多边形方法介绍
Dec 29 Javascript
React Native使用Modal自定义分享界面的示例代码
Oct 31 Javascript
vue iview实现动态路由和权限验证功能
Apr 17 Javascript
vue使用el-upload上传文件及Feign服务间传递文件的方法
Mar 15 Javascript
在vue项目中使用codemirror插件实现代码编辑器功能
Aug 27 Javascript
javascript canvas API内容整理
Feb 16 Javascript
vue计算属性+vue中class与style绑定(推荐)
Mar 30 Javascript
jQuery中table数据的值拷贝和拆分
Mar 19 #Javascript
js实现旋转木马效果
Mar 17 #Javascript
jQuery实现验证码功能
Mar 17 #Javascript
基于vue.js轮播组件vue-awesome-swiper实现轮播图
Mar 17 #Javascript
node操作mysql数据库实例详解
Mar 17 #Javascript
vue.js从安装到搭建过程详解
Mar 17 #Javascript
超简单的Vue.js环境搭建教程
Mar 17 #Javascript
You might like
一些使用频率比较高的php函数
2008/10/03 PHP
PHP开发的一些注意点总结
2010/10/12 PHP
解析:通过php socket并借助telnet实现简单的聊天程序
2013/06/18 PHP
浅析php静态方法与非静态方法的用法区别
2016/05/17 PHP
PHP中利用sleep函数实现定时执行功能实现代码
2016/08/25 PHP
JavaScript包装对象使用介绍
2013/08/29 Javascript
jquery通过visible来判断标签是否显示或隐藏
2014/05/08 Javascript
JavaScript实现点击文字切换登录窗口的方法
2015/05/11 Javascript
Perl Substr()函数及函数的应用
2015/12/16 Javascript
Jquery表单验证失败后不提交的解决方法
2016/10/18 Javascript
Vue.js双向绑定实现原理详解
2016/12/22 Javascript
详解JavaScript 中getElementsByName在IE中的注意事项
2017/02/21 Javascript
基于jQuery实现的单行公告活动轮播效果
2017/08/23 jQuery
基于es6三点运算符的使用方法(实例讲解)
2017/10/12 Javascript
layui 根据后台数据动态创建下拉框并同时默认选中的实例
2019/09/02 Javascript
JS倒计时两种实现方式代码实例
2020/07/27 Javascript
返回上一个url并刷新界面的js代码
2020/09/12 Javascript
Python模仿POST提交HTTP数据及使用Cookie值的方法
2014/11/10 Python
Python制作爬虫抓取美女图
2016/01/20 Python
python爬虫基本知识
2018/03/05 Python
Python网页正文转换语音文件的操作方法
2018/12/09 Python
python 通过SSHTunnelForwarder隧道连接redis的方法
2019/02/19 Python
用django-allauth实现第三方登录的示例代码
2019/06/24 Python
如何利用python给图片添加半透明水印
2019/09/06 Python
css3弹性盒模型实例介绍
2013/05/27 HTML / CSS
美国最受欢迎的度假目的地优惠套餐:BookVIP
2018/09/27 全球购物
static函数与普通函数有什么区别
2015/12/25 面试题
医学生个人求职信范文
2013/09/24 职场文书
亲属关系公证书
2014/04/08 职场文书
幼儿园课题方案
2014/06/09 职场文书
普通党员自我剖析材料
2014/10/07 职场文书
2015年五一劳动节演讲稿
2015/03/18 职场文书
中秋节晚会开场白
2015/05/29 职场文书
原来闭幕词是这样写的呀!
2019/07/01 职场文书
Mysql 性能监控及调优
2021/04/06 MySQL
Python中使用ipython的详细教程
2021/06/22 Python