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通过class来获取元素实现代码
Feb 20 Javascript
禁止ajax缓存获取程序最新数据的方法
Nov 19 Javascript
使用javascript实现有效时间的控制,并显示将要过期的时间
Jan 02 Javascript
js使用removeChild方法动态删除div元素
Aug 01 Javascript
JavaScript中constructor()方法的使用简介
Jun 05 Javascript
js实现table添加行tr、删除行tr、清空行tr的简单实例
Oct 15 Javascript
JS原生带小白点轮播图实例讲解
Jul 22 Javascript
解决html-jquery/js引用外部图片时遇到看不了或出现403的问题
Sep 22 jQuery
js导出Excel表格超出26位英文字符的解决方法ES6
Nov 15 Javascript
在vue中给列表中的奇数行添加class的实现方法
Sep 05 Javascript
jquery获取并修改触发事件的DOM元素示例【基于target 属性】
Oct 10 jQuery
vue.js路由mode配置之去掉url上默认的#方法
Nov 01 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常用代码
2006/11/23 PHP
PHP开发中常用的字符串操作函数
2011/02/08 PHP
解析PHP实现多进程并行执行脚本
2013/06/18 PHP
php 下载保存文件保存到本地的两种实现方法
2013/08/12 PHP
php实现refresh刷新页面批量导入数据的方法
2014/12/23 PHP
php操作mongoDB实例分析
2014/12/29 PHP
PHP实现的迷你漂流瓶
2015/07/29 PHP
ThinkPHP中create()方法自动验证表单信息
2017/04/28 PHP
PHP排序算法之直接插入排序(Straight Insertion Sort)实例分析
2018/04/20 PHP
PHP操作Postgresql封装类与应用完整实例
2018/04/24 PHP
thinkphp5框架实现数据库读取的数据转换成json格式示例
2019/10/10 PHP
PHP pthreads v3下的Volatile简介与使用方法示例
2020/02/21 PHP
对JavaScript的eval()中使用函数的进一步讨论
2008/07/26 Javascript
js身份证验证超强脚本
2008/10/26 Javascript
js 单引号 传递方法
2009/06/22 Javascript
WEB 浏览器兼容 推荐收藏
2010/05/14 Javascript
Javascript Request获取请求参数如何实现
2012/11/28 Javascript
自己写的Javascript计算时间差函数
2013/10/28 Javascript
js判断设备是否为PC并调整图片大小
2014/02/12 Javascript
简单学习JavaScript中的for语句循环结构
2015/11/10 Javascript
JQuery遍历元素的父辈和祖先的方法
2016/09/18 Javascript
jQuery基于ajax实现页面加载后检查用户登录状态的方法
2017/02/10 Javascript
js获取一组日期中最近连续的天数
2017/05/25 Javascript
js中实例与对象的区别讲解
2019/01/21 Javascript
解决vue admin element noCache设置无效的问题
2019/11/12 Javascript
python实现数组插入新元素的方法
2015/05/22 Python
pyqt5 lineEdit设置密码隐藏,删除lineEdit已输入的内容等属性方法
2019/06/24 Python
Jupyter notebook 远程配置及SSL加密教程
2020/04/14 Python
canvas绘图按照contain或者cover方式适配并居中显示
2019/02/18 HTML / CSS
当当网官方旗舰店:中国图书销售夺金品牌
2018/04/02 全球购物
Juicy Couture Beauty官方网站:香水和化妆品
2019/03/12 全球购物
Java面试题:Java类的Main方法如果是Private将会怎么样
2016/08/18 面试题
干部选拔任用方案
2014/05/26 职场文书
超市客服工作职责
2014/06/11 职场文书
2015年度个人业务工作总结
2015/04/27 职场文书
python基础之类属性和实例属性
2021/10/24 Python