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 相关文章推荐
使用Json比用string返回数据更友好,也更面向对象一些
Sep 13 Javascript
jquery 操作iframe的几种方法总结
Dec 13 Javascript
js左右弹性滚动对联广告代码分享
Feb 19 Javascript
javascript使用switch case实现动态改变超级链接文字及地址
Dec 16 Javascript
限制上传文件大小和格式的jQuery插件实例
Jan 24 Javascript
jquery Deferred 快速解决异步回调的问题
Apr 05 Javascript
常用原生JS兼容性写法汇总
Apr 27 Javascript
微信小程序 动态的设置图片的高度和宽度详解及实例代码
Feb 24 Javascript
p5.js临摹动态图形的方法
Oct 23 Javascript
jQuery实现简单评论功能
Aug 19 jQuery
springboot+vue实现文件上传下载
Nov 17 Vue.js
vue实现轮播图帧率播放
Jan 26 Vue.js
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
建站常用13种PHP开源CMS比较
2009/08/23 PHP
ThinkPHP利用PHPMailer实现邮件发送实现代码
2013/09/26 PHP
php实现图片缩放功能类
2013/12/18 PHP
成为好程序员必须避免的5个坏习惯
2014/07/04 PHP
laravel 框架执行流程与原理简单分析
2020/02/01 PHP
使用Javascript接收get传递的值的代码
2011/11/30 Javascript
js实现倒计时(距离结束还有)示例代码
2013/07/24 Javascript
js监听鼠标事件控制textarea输入字符串的个数
2014/09/29 Javascript
jquery实现翻动fadeIn显示的方法
2015/03/05 Javascript
java中String类型变量的赋值问题介绍
2016/03/23 Javascript
fullpage.js全屏滚动插件使用实例
2016/09/06 Javascript
JS组件系列之使用HTML标签的data属性初始化JS组件
2016/09/14 Javascript
jQuery Jsonp跨域模拟搜索引擎
2017/06/17 jQuery
JavaScript中附件预览功能实现详解(推荐)
2017/08/15 Javascript
Bootstrap Tooltip显示换行和左对齐的解决方案
2017/10/11 Javascript
JS简单实现查看文档创建日期、修改日期和文档大小的方法示例
2018/04/08 Javascript
vue监听滚动事件的方法
2020/12/21 Vue.js
[54:27]TNC vs Serenity 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
Python切片工具pillow用法示例
2018/03/30 Python
python读取xlsx的方法
2018/12/25 Python
使用Python实现企业微信的自动打卡功能
2019/04/30 Python
如何不用安装python就能在.NET里调用Python库
2019/07/12 Python
python对Excel的读取的示例代码
2020/02/14 Python
HTML5 Plus 实现手机APP拍照或相册选择图片上传功能
2016/07/13 HTML / CSS
HTML5超文本标记语言的实现方法
2020/09/24 HTML / CSS
韩国江南富人区高端时尚百货商场:Galleria(格乐丽雅)
2018/03/27 全球购物
图库照片、免版税图片、矢量艺术、视频片段:Depositphotos
2019/08/02 全球购物
Bravofly德国:预订廉价航班和酒店
2019/09/22 全球购物
金融专业个人求职信
2013/09/22 职场文书
中医专业职业生涯规划书范文
2014/01/04 职场文书
水果连锁超市创业计划书
2014/01/24 职场文书
四风个人对照检查材料思想汇报(办公室通用版)
2014/10/07 职场文书
3.15消费者权益日活动总结
2015/02/09 职场文书
未中标通知书
2015/04/17 职场文书
关于感恩的作文
2019/08/26 职场文书
SpringBoot深入分析讲解监听器模式下
2022/07/15 Java/Android