JSONP
JSONP(JSON with padding) 是一种跨域访问的机制。
跨域访问
定义:跨域是指从一个域名的网页去请求另一个域名的资源。比如从http://www.baidu.com/ 页面去请求 http://www.google.com 的资源。跨域的严格一点的定义是:只要 协议,域名,端口有任何一个的不同,就被当作是跨域。
跨站攻击
传统上,浏览器的实现禁止 XMLHttpRequest
请求跨域访问,因为这样会引发安全问题,如跨站攻击。
跨站攻击例:
- A网站通过以下请求发帖:http://example.com/bbs/create_post.php?title=标题&content=内容
- 若Attacker在B网站发帖包含以下链接:http://example.com/bbs/create_post.php?title=我是脑残&content=哈哈
- 则只要在B网站点了以上链接的victim,都会不知情的发帖。由于example网站保存了cookie,因此有victim的authentication
跨域使用场景
有时公司内部有多个不同的子域,比如一个是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
<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
20var 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 | $.getJSON("http://crossdomain.com/services.php?callback=?", function(json){ |
$.ajax
1 | $.ajax({ |
AngularJS实现
1 | $http.jsonp('https://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=JSON_CALLBACK') |