JSONP简介

JSONP

JSONP(JSON with padding) 是一种跨域访问的机制。

跨域访问

定义:跨域是指从一个域名的网页去请求另一个域名的资源。比如从http://www.baidu.com/ 页面去请求 http://www.google.com 的资源。跨域的严格一点的定义是:只要 协议,域名,端口有任何一个的不同,就被当作是跨域。

跨站攻击

传统上,浏览器的实现禁止 XMLHttpRequest 请求跨域访问,因为这样会引发安全问题,如跨站攻击
跨站攻击例:

跨域使用场景

有时公司内部有多个不同的子域,比如一个是location.company.com,而应用是放在app.company.com , 这时想从 app.company.com去访问 location.company.com 的资源就属于跨域。

如何跨域

首先,要知道HTML中的<script><img> 标签的src属性是可以跨域访问的。JSONP正是利用了这一点进行跨域访问。

为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

JSONP缺点

  • 由于script标签仅支持get方法,因此JSONP也仅支持get请求
  • 需要服务器配合返回指定格式的数据

简单实现

  • 客户端

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <!DOCTYPE html>
    <html>
    <head>
    <title></title>
    <script type="text/javascript">
    // 得到航班信息查询结果后的回调函数
    var flightHandler = function(data){
    alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。');
    };
    //把callback函数赋给window对象,供script回调
    window.flightHandler = flightHandler;

    // 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
    var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler";

    // 创建script标签,设置其属性
    var script = document.createElement('script');
    script.setAttribute('src', url);
    // 把script标签加入head,此时调用开始
    document.getElementsByTagName('head')[0].appendChild(script);
    </script>
    </head>
    <body></body>
    </html>
  • 服务器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    var http = require('http');
    var urllib = require('url');

    var port = 8080;
    var data = {'data':'world'};

    http.createServer(function(req,res){
    var params = urllib.parse(req.url,true);
    if(params.query.callback){
    console.log(params.query.callback);
    //jsonp
    var str = params.query.callback + '(' + JSON.stringify(data) + ')';
    res.end(str);
    } else {
    res.end();
    }

    }).listen(port,function(){
    console.log('jsonp server is on');
    });

JQuery实现

$.getJSON

1
2
3
$.getJSON("http://crossdomain.com/services.php?callback=?", function(json){
alert('您查询到航班信息:票价: ' + json.price + ' 元,余票: ' + json.tickets + ' 张。');
});

$.ajax

1
2
3
4
5
6
7
8
9
10
11
12
13
$.ajax({
type: "get",
url: "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998",
dataType: "jsonp",
jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
jsonpCallback:"flightHandler",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
success: function(json){
alert('您查询到航班信息:票价: ' + json.price + ' 元,余票: ' + json.tickets + ' 张。');
},
error: function(){
alert('fail');
}
});

AngularJS实现

1
2
3
4
5
6
$http.jsonp('https://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=JSON_CALLBACK')
.success(function(data){
alert('success:'+data);
}).error(function(err){
alert('error:'+err);
});