jsonp原理及使用


Posted in Javascript onOctober 28, 2013

初识jsonp
jsonp 全称是JSON with Padding,是为了解决跨域请求资源而产生的解决方案。很多时候我们需要在客户端获取服务器数据进行操作,一般我们会使用ajax+webservice做此事,但是如果我们希望获取的数据和当前页面并不是一个域,著名的同源策略(不同域的客户端脚本在没明确授权的情况下,不能读写对方的资源)会因为安全原因决绝请求,也就是我们不能向其它域直接发送请求以获取资源。
在localhot域上有一个books.php,里面包含脚本对test.com域的books.php发送get请求,希望获取其book列表资源,这就是一个跨域请求资源

$.ajax({
            type:'get',
            url:'http://test.com/books.php'
        });

页面会报一个这样的错误:XMLHttpRequest cannot load http://test.com/books.php. Origin http://localhost is not allowed by Access-Control-Allow-Origin.jsonp是为了解决这个问题出现的。

jsonp原理
虽然有同源策略的限制,但是并不是HTML上所有资源都必须是同一个域的,我们常见的页面为了节省流量或加载速度采用Google或微软的 jQuery CDN,在页面上我们可以这样写就可以引用jQuery了

<script  type="text/javascript"
    src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js">
</script>

iframe、img、style、script等元素的src属性可以直接向不同域请求资源,jsonp正式利用script标签跨域请求资源的

简单实现
localhost的books.php希望获得域test.com的books列表,在域test.com内book列表存储在books.xml中
test.com/books.xml

<?xml version="1.0"?>
<books>
    <book name="JavaScript: The Defiitive Guide" publisher="O'Reilly Media, Inc.">
        <author>David Flanagan</author>
    </book>
    <book name="PHP anf MySQL Web Development" publisher="Perason Education">
        <author>Luke Welling</author>
        <author>Laura Thomson</author>
    </book>
    <book name="HTTP: The Defiitive Guide" publisher="O'Reilly Media, Inc.">
        <author>David Courley</author>
        <author>Brian Totty</author>
    </book>
</books>

明显JavaScript不能直接获取books.xml,在test.com中需要有一个机制将xml转化为json(这也就是为什么叫jsonp,其实和ajax一样,返回的数据不一定是json格式,只是json很好用),并动态拼接一条javascript调用语句返回,这个例子中直接使用php页面拼接
test.com/bookservice.php
<?php
    $path=$_SERVER["DOCUMENT_ROOT"].'/books.xml';
    $json=json_encode(simplexml_load_file($path));
    $callbackFn=$_GET['callback'];
    echo "$callbackFn($json);";
?>

这样首先把xml文件内容转换成一个json对象
{"book":[
{"@attributes":{"name":"JavaScript: The Defiitive Guide","publisher":"O'Reilly Media, Inc."},"author":"David Flanagan"},
{"@attributes":{"name":"PHP anf MySQL Web Development","publisher":"Perason Education"},"author":["Luke Welling","Laura Thomson"]},
{"@attributes":{"name":"HTTP: The Defiitive Guide","publisher":"O'Reilly Media, Inc."},"author":["David Courley","Brian Totty"]}
]}

然后拼接为一条javascript语句交给localhost去处理,当然test.com并不知道应该拼接的方法名叫什么,需要localhost在发送请求的时候在url中传入一个叫callback(这个也随便,两边同步就行)的参数指明。看看localhost怎么发送请求吧
localhost/books.php
<!DOCTYPE html>
<html>
<head>
    <title>Books</title>
    <?php include('/components/headerinclude.php');?></head>
    <style type="text/css">
        .book-title
        {
            font-size: 15px;
            font-weight:bold;
            margin-top:6px;
        }
        .book-info
        {
            color:#ccc;
            font-style:italic;
            border-bottom:dashed 1px #ccc;
        }
    </style>
</head>
<body>
    <div style="margin:20px;">
        <div style="font-size:16px;font-weight:bold;">Books</div>
        <div id="books">
        </div>
    </div>
</body>
</html>

我们希望在id为books的div中展示所有book,先添加一个用以显示book的javascript函数,也就是获取到数据后的回调函数,结合上面拼接的json格式可以这么写
function displayBooks(books){
            var books=books.book;
            var booksContainer=document.getElementById('books');
            for(var i=0;i<books.length;i++){
                var tmp=Array();
                tmp.push('<div class="book-title">'+books[i]['@attributes'].name+'</div>');
                tmp.push('<div class="book-info">');
                tmp.push('<div>Publisher: '+books[i]['@attributes'].publisher+'</div>');
                tmp.push('<div>Author(s): ');
                if(typeof books[i].author=='string'){
                    tmp.push(books[i].author);
                }else{
                    var authors=books[i].author;
                    for(var j=0;j<authors.length;j++){
                        tmp.push(authors[j]+' ');
                    }
                }
                tmp.push('</div>'); //end of author
                tmp.push('</div>'); //end of book info
                booksContainer.innerHTML+=tmp.join('');
            }
        }

然后是关键的jsonp请求的方法了
function getBooks(){
            var script=document.createElement('script');
            script.setAttribute('type','text/javascript');
            script.setAttribute('src','http://test.com/bookservice.php?callback=displayBooks');
            document.body.appendChild(script);
        }
        getBooks();

在getbooks()方法中动态创建了一个script标签,设置其src为test.com提供的获取数据的service接口并传入回调函数,这样我们可以看看页面的反应,在Chrome控制台下可以看到这条请求
jsonp原理及使用

我们就可以在localhost下获取test.com的books了
jsonp原理及使用

jquery实现
在jquery中也有对jsonp的封装,不过jquery把其放到了ajax中,不明白为什么,毕竟这东西和ajax不太一样。写一个jQuery版的

function getBooks(){
            $.ajax({
                type:'get',
                url:'http://test.com/bookservice.php',
                dataType:'jsonp',
                jsonp:'callback',
                jsonpCallback:'displayBooks'
            });
        }

看起来完全一样,不过方便了很多,不用自己创建script标签神马的了,指明dataType为jsonp,回调函数不放在url内了,而是使用两个参数分别指明。

安全性问题
当然使用jsonp会在一定程度上造成安全性问题,如果请求的站点不是新人站点,那么可能会在返回的方法调用中包含一些恶意代码。所以尽量向信任的站点发送请求。另外xss也经常会利用jsonp向站点注入恶意代码。

Javascript 相关文章推荐
JavaScript 节点操作 以及DOMDocument属性和方法
Dec 06 Javascript
IE8 下的Js错误HTML Parsing Error...
Aug 14 Javascript
HTA版JSMin(省略修饰语若干)基于javascript语言编写
Dec 24 Javascript
Javascript学习笔记2 函数
Jan 11 Javascript
javascript 三种方法实现获得和设置以及移除元素属性
Mar 20 Javascript
javascript Array.prototype.slice的使用示例
Nov 14 Javascript
JS中判断字符串中出现次数最多的字符及出现的次数的简单实例
Jun 03 Javascript
基于JavaScript实现的希尔排序算法分析
Apr 14 Javascript
bootstrap table方法之expandRow-collapseRow展开或关闭当前行数据
Aug 09 Javascript
原生js代码能实现call和bind吗
Jul 31 Javascript
vue组件中传值EventBus的使用及注意事项说明
Nov 16 Javascript
JavaScript实现外溢动态爱心的效果的示例代码
Mar 21 Javascript
JS实现一键回顶功能示例代码
Oct 28 #Javascript
简单的js表单验证函数
Oct 28 #Javascript
自己写的Javascript计算时间差函数
Oct 28 #Javascript
Textarea根据内容自适应高度
Oct 28 #Javascript
将json当数据库一样操作的javascript lib
Oct 28 #Javascript
一个JavaScript变量声明的知识点
Oct 28 #Javascript
Javascript实现页面跳转的几种方式分享
Oct 26 #Javascript
You might like
比较全的PHP 会话(session 时间设定)使用入门代码
2008/06/05 PHP
PHP 编写大型网站问题集
2010/05/07 PHP
在windows服务器开启php的gd库phpinfo中未发现
2013/01/13 PHP
php颜色转换函数hex-rgb(将十六进制格式转成十进制格式)
2013/09/23 PHP
简单的php新闻发布系统教程
2014/05/09 PHP
PHP date函数常用时间处理方法
2015/05/11 PHP
基于PHP实现短信验证码发送次数限制
2020/07/11 PHP
清除网页历史记录,屏蔽后退按钮!
2008/12/22 Javascript
JavaScript 常用函数库详解
2009/10/21 Javascript
Node.js中require的工作原理浅析
2014/06/24 Javascript
js实现hashtable的赋值、取值、遍历操作实例详解
2016/12/25 Javascript
javascript获取指定区间范围随机数的方法
2017/09/08 Javascript
AngularJS中scope的绑定策略实例分析
2017/10/30 Javascript
mui框架 页面无法滚动的解决方法(推荐)
2018/01/25 Javascript
详解Node.js一行命令上传本地文件到服务器
2019/04/22 Javascript
微信小程序实现一个简单swiper代码实例
2019/12/30 Javascript
JavaScript碰撞检测原理及其实现代码
2020/03/12 Javascript
vue计算属性+vue中class与style绑定(推荐)
2020/03/30 Javascript
Vue 实现创建全局组件,并且使用Vue.use() 载入方式
2020/08/11 Javascript
详解Python中列表和元祖的使用方法
2015/04/25 Python
python中异常报错处理方法汇总
2016/11/20 Python
Python中easy_install 和 pip 的安装及使用
2017/06/05 Python
Python中装饰器学习总结
2018/02/10 Python
PyQt5 QSerialPort子线程操作的实现
2018/04/21 Python
Python Logging 日志记录入门学习
2018/06/02 Python
Python socket模块实现的udp通信功能示例
2019/04/10 Python
PyPDF2读取PDF文件内容保存到本地TXT实例
2020/05/12 Python
使用CSS3制作饼状旋转载入效果的实例
2015/06/23 HTML / CSS
美国知名运动产品零售商:Foot Locker
2016/07/23 全球购物
白俄罗斯在线大型超市:e-dostavka.by
2019/07/25 全球购物
params有什么用
2016/03/01 面试题
采购部部长岗位职责
2014/02/06 职场文书
库房管理员岗位职责
2015/02/12 职场文书
寻找成龙观后感
2015/06/12 职场文书
励志语录:时光飞逝,请学会珍惜所有的人和事
2020/01/16 职场文书
react如何快速设置文件路径别名
2021/04/28 Javascript