前言:

     
明天,无意间看到自身某些文件夹下有个JSONP的事物。稳步记忆起,那几个东西是前边想写的贰个demo,也不精晓是多长时间在此之前了,可是不清楚怎么的,给忘那边了。那么,就趁这么些机遇把它形成吗,其实也说不上是三个demo,正是八个小规模试制验,固然,网上也早就有过多关于JSONP的稿子和例子了,然而多少东西看看很不难,不亲自试一下总认为不扎实。笔者今天干什么要尝试,一方面也是平常在网上看看稍微网址供给跨域获得数量,但是当前本人做的类别中又尚未相关需要,于是很好奇,于是就有了那篇小说,于是……那就从头此次操演吧。

一 什么是JSONP

   JSONP全称:JSON with Padding

  
看到名字,好像说,JSONP是JSON的怎么?或者有人会问,什么是JSON呢?即便有同学还不清楚JSON,能够先去询问下JSON,然后再持续本文的开卷可能会更加好。一言以蔽之,JSON是一种数据调换格式,在我们通过ajax技术获取数据的时候,能够以XML大概JSON那样的格式进行传递。ajax即使好用,可是也有蒙受困难的时候,比如你须要跨域获取数据。这年,普通的ajax获取情势就不太简单了,那时候,JSONP就足以协理了。那里再补偿下前面提到跨域难题,跨域其实简单来说就是,比如您自身写了1个网址把它配备到域名是www.a.com的服务器上,然后您能够不用压力的运用ajax请求www.a.com/users.json 
的数量。 可是,当要你通过普通ajax格局呼吁www.b.com域名下的www.b.com/users.json的数据时,就没那么不难了,在后边的小规模试制验中,能够观望这一气象。既然使用普通的ajax技术无法到位,那么JSONP又是什么样成功的吧?

2 JSONP的基本原理

   JSONP可以实现跨域,那要归功于强大的<script></script>成分标签。除了我们会在它中间写js代码外,也常常会在网址中经过它的src属性引进外部js文件,关键就在此,大家的引进的js文件也得以不是同3个域下的。那么大家也就能够将本来需求获得的JSON数据写到js文件中去,然后再赢得。但是,不幸的事体究竟产生了,当大家把一段JSON格式的数据,例如:

1 {"id" : "1","name" : "小王"}

写入js文件,然后经过<script>成分引进后,却报错了。原因是<script>标签成分依然老实巴交的,因为它便是负担实施js的,所以你非凡JSON格式的数目它也会坚决的作为js代码去实践,而那些数据根本不合乎js语法,于是就很喜剧的失误了。但以此出错,同样却带给了我们答案,不是吗?既然不吻合js语法不行,大家搞个适合的不就能够了。那里一种常用的方式就是回来三个函数callback({“id”
: “一”,”name” : “小王”});
的履行语句就足以了。那里的callback命名不是必须的,你能够换别的喜欢的名字。那里只是强调那是个回调函数才如此写。回调函数确实强大啊,要使得那里能够实施该函数,那么那些函数必须在伊始就曾经被我们提前定义了。大家在开头就定义好:

function callback(data){
    alert(data.name);
}

其实那些简单掌握,普通的函数执行恐怕我们都知道,在<script>标签中间先定义上边的函数,可是该函数并不会运作,因为您没实施调用,当你跟着在代码中写上
callback({“id” : “1”,”name” :
“小王”});就顺遂的实践了。而JSONP所做的正是其一业务,只但是调用的言辞从远程服务器传来,动态参与到您的页面中去实践而已。到此处只剩下最后一步了,正是告诉服务器端重回哪个名称的函数执行,这些也好办,将函数名以一个查询参数传递到后台告诉它名字就好了,类似:

http://www.b.com/getUsers.json?callback=getUsers

接下来在服务器端处理,得到参数callback的值,然后将数据填充到getUser(data);的函数参数中去,那里的data。重临前台页面后,便得以实行并得到data数据了。到此,也好不简单知道了JSON
with
Padding中的Padding(填充)了。关于JSONP的基础理论部分就结束了,剩下的情节就剩下实验部分了。

 

三 JSONP小实验

  •   实验环境:windows操作系统。
  •   开发工具:NotePad++。
  •   开发语言:Node.js。
  •   前台使用插件:jQuery。

 开端了,那里选拔Node.js,没任何原因,作者只是随手抓到它了,你当然也得以用asp.net,java
servlet,php,ruby,Golang等之类你欣赏的去尝试。因为只实验JSONP,没多少东西,所以Node.js中也尚未应用第一方的框架(不过后来有个别后悔了,多写了好多……)。

第1须求效法七个域,因为自己在windows下,所以能够修改host文件,添加

jQuery 1

八个域名映射到本机回送地址1贰七.0.0.1。然后开端写代码:

创制七个Node.js的行使,贰个是appA.js,二个appB.js。首先,大家尝试通过普通ajax获取同域的数码:

appB.js代码:

 

jQuery 2jQuery 3View Code

 1 var http = require('http'),
 2       url = require('url'),
 3       fs  = require('fs'),
 4       path = require('path');
 5      
 6 
 7 function getFile(localPath,mimeType,res){
 8     fs.readFile(localPath,function(err,contents){
 9         if(!err){
10             res.writeHead(200,{
11                 'Content-Type' : mimeType,
12                 'Content-length' : contents.length
13             
14             });
15             res.end(contents);
16         }else{
17             res.writeHead(500);
18             res.end();
19         }
20     
21     });
22 }
23 http.createServer(function(req,res){
24     var urlPath = url.parse(req.url).pathname;
25     var fileName = path.basename(req.url) || 'index.html',
26          suffix  = path.extname(fileName).substring(1),
27          dir = path.dirname(req.url).substring(1),
28          localPath = __dirname + '\\';
29     
30 
31     if(suffix === 'js'){
32         localPath += (dir ? dir + '\\' : '') + fileName;
33         path.exists(localPath,function(exists){
34             if(exists){
35                 getFile(localPath,'js',res);
36             }else{
37                 res.writeHead(404);
38                 res.end();
39             }
40             
41         });
42         
43     }else{
44         if(urlPath === '/index'){
45         res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'});
46         var html = '<!DOCTYPE html>'
47                     +'<head>'
48 +'<script type="text/javascript" src="jquery.js"></script>'
49                     
50                     +'<script type="text/javascript" src="http://www.a.com:8088/index?callback=getFollowers"></script>'
51                     +'<script>'
52                     +'$(function(){'
53                     +  ''
54                     +  '$("#getFo").click(function(){'
55                     +'    $.ajax({'
56                     +            'url:"http://www.b.com:9099/followers.json",'
57                     +       'type:"get",'
58                     +       'success:function(json){'
59                     +       '    alert(json.users[0].name);'
60                     +       '}'
61                     +        '});'
62                     +     ''
63                     +    '});'
64                     +'});'
65                     +'</script>'
66                     +'</head>'
67                     +'<body>'
68                     +'<h1>hello i am server b </h1>'
69                     +'<input id="getFo" type="button" value="获取我的粉丝"/>'
70                     +'</body>'
71                     +'</html>';
72         res.write(html);
73         res.end();
74     }else if(urlPath === '/followers.json'){
75         res.writeHead(200,{'Content-Type':'application/json;charset=utf-8'});
76         var followers = {
77                                 "users" : [
78                                     {"id" : "1","name" : "小王"},
79                                     {"id" : "2","name" : "小李"}
80                                   ]
81                                 };
82         var fjson = JSON.stringify(followers);
83         res.end(fjson);
84     }else{
85         res.writeHead(404,{'Content-Type':'text/html;charset=utf-8'});
86         res.end('page not found');
87     }
88     
89 }
90     
91     
92 }).listen(9099);
93 console.log('Listening app B at 9099...');

 jQuery 4

以上截图是ajax请求数据部分。大家开拓浏览器,输入地方后,如下:

jQuery 5

此地有个按钮获取自笔者的观众,ajax就从url:”http://www.b.com:9099/followers.json该源获得多少,那几个数目在代码中,大家也足以找到,就是

jQuery 6

 当点击获取后,如下:

jQuery 7

 成功,没难点,我们再复制一份壹样的代码,另存为appA.js,然后修改listen端口:

jQuery 8

修改appB.js中ajax请求的URL为http://www.a.com:8088/followers.json ,现在是appB服务器自身是http://www.b.com:9099/index 而去请求www.a.com下的数码===》运维它

jQuery 9

下一场点击获取观者按钮会发现:

jQuery 10

 真的尚未取到数据。。。。。。

再尝试JSONP的艺术,大家修改appB.js如下:

jQuery 11jQuery 12View Code

 1 var http = require('http'),
 2       url = require('url'),
 3       fs  = require('fs'),
 4       path = require('path');
 5      
 6 
 7 function getFile(localPath,mimeType,res){
 8     fs.readFile(localPath,function(err,contents){
 9         if(!err){
10             res.writeHead(200,{
11                 'Content-Type' : mimeType,
12                 'Content-length' : contents.length
13             
14             });
15             res.end(contents);
16         }else{
17             res.writeHead(500);
18             res.end();
19         }
20     
21     });
22 }
23 http.createServer(function(req,res){
24     var urlPath = url.parse(req.url).pathname;
25     var fileName = path.basename(req.url) || 'index.html',
26          suffix  = path.extname(fileName).substring(1),
27          dir = path.dirname(req.url).substring(1),
28          localPath = __dirname + '\\';
29     
30 
31     if(suffix === 'js'){
32         localPath += (dir ? dir + '\\' : '') + fileName;
33         path.exists(localPath,function(exists){
34             if(exists){
35                 getFile(localPath,'js',res);
36             }else{
37                 res.writeHead(404);
38                 res.end();
39             }
40             
41         });
42         
43     }else{
44         if(urlPath === '/index'){
45         res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'});
46         var html = '<!DOCTYPE html>'
47                     +'<head>'
48                     +'<script type="text/javascript">var getFollowers= function(data){alert(decodeURIComponent(data.users[0].name));};</script>'
49                     +'<script type="text/javascript" src="jquery.js"></script>'
50                     
51                     +'<script type="text/javascript" src="http://www.a.com:8088/index?callback=getFollowers"></script>'
52                     +'<script>'
53                     +'$(function(){'
54                     +  ''
55                     +  '$("#getFo").click(function(){'
56                     +'    $.ajax({'
57                     +            'url:"http://www.a.com:8088/followers.json",'
58                     +       'type:"get",'
59                     +       'success:function(json){'
60                     +       '    alert(json.users[0].name);'
61                     +       '}'
62                     +        '});'
63                     +     ''
64                     +    '});'
65                     +'});'
66                     +'</script>'
67                     +'</head>'
68                     +'<body>'
69                     +'<h1>hello i am server b </h1>'
70                     +'<input id="getFo" type="button" value="获取我的粉丝"/>'
71                     +'</body>'
72                     +'</html>';
73         res.write(html);
74         res.end();
75     }else if(urlPath === '/followers.json'){
76         res.writeHead(200,{'Content-Type':'application/json;charset=utf-8'});
77         var followers = {
78                                 "users" : [
79                                     {"id" : "1","name" : "小王"},
80                                     {"id" : "2","name" : "小李"}
81                                   ]
82                                 };
83         var fjson = JSON.stringify(followers);
84         res.end(fjson);
85     }else{
86         res.writeHead(404,{'Content-Type':'text/html;charset=utf-8'});
87         res.end('page not found');
88     }
89     
90 }
91     
92     
93 }).listen(9099);
94 console.log('Listening app B at 9099...');

 注意看4八行和5壹行,4八行定义了回调函数,51行通过<script>标签,请求区别域的数量,当中传递参数callback=getFollowers

接下来修改appA.js如下:

jQuery 13jQuery 14View Code

 1 var http = require('http'),
 2      url = require('url'),
 3      querystring = require('querystring');
 4 
 5 http.createServer(function(req,res){
 6     
 7     var path = url.parse(req.url).pathname;
 8     var qs = querystring.parse(req.url.split('?')[1]),
 9          json;
10     if(qs.callback){
11         var followers = {
12                                 users : [{id:'1',name:encodeURIComponent('小王')}]
13                                 };
14         var fjson = JSON.stringify(followers);
15         console.log(fjson);
16         json = qs.callback + "(" + fjson + ");";
17         res.writeHead(200,{
18                         'Content-Type':'application/json',
19                         'Content-Length' : json.length
20                         });
21         res.end(json);
22     
23     }
24     
25     if(path === '/index'){
26         res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'});
27         res.end('home');
28     }else if(path === '/followers.json'){
29         res.writeHead(200,{'Content-Type':'application/json;charset=utf-8'});
30         var followers = {
31                                 "users" : [
32                                     {"id" : "1","name" : "小王"},
33                                     {"id" : "2","name" : "小李"}
34                                   ]
35                                 };
36         var fjson = JSON.stringify(followers);
37         res.end(fjson);
38     }else{
39         res.writeHead(404,{'Content-Type':'text/html;charset=utf-8'});
40         res.end('page not found');
41     }
42     res.end('hello');
43 }).listen(8088);
44 console.log('Listening app A at 8088...');

 第八行-二三行,大家处理了传递的参数,并将数据填充到函数参数,并发送到请求者那边。再一次运维多少个程序,刷新http://www.b.com:9099/index便平素获取a域下的数据了,就好像马到功成了。但是,作者不想及时执行呀,小编也要和前面一样,点击按钮再拿走,如何做?那么些也差不多。只必要当大家点击的时候动态的引进<script>就足以了,修改click事件处理部分的代码:

1 $("#getFo").click(function(){
2 $("<script><//script>").attr("src","http://www.a.com:8088/index?callback=getFollowers").appendTo("body");
3 });

双重重启服务器,当点击按钮就足以获取数据了。接下来,大家再看看jQuery又是何等处理JSONP的呢?

 

 

四 jQuery中处理JSONP

  要因而jQuery使用JSONP是老大有利于的,只须要修改最开始的ajax部分代码如下:

1 $.ajax({
2     url:"http://www.a.com:8088/index",
3     dataType:"jsonp",
4     jsonp:"callback",
5     type:"get",
6     success:function(json){
7     alert(decodeURIComponent(json.users[0].name));
8     }
9 });

里头,jsonp指明了querystring的key为callback,value假如不点名,jQuery会暗许随机生成3个名号:

1 var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );

 

伍 JSONP或然滋生的安全性难题

  由JSONP只怕滋生的安全难点根本是唯恐汇合临CSHavalF/XS科雷傲F的抨击,而使得简单受到该攻击的也恰好是上文中一贯提到的JSONP的表征–能够跨源访问财富。普通的CS奥迪Q5F/XSRAV4F攻击,仅仅大概应用受攻击用户,骗取服务器的亲信,那样就可以效仿受攻击者对服务器进行壹些有加害的伸手,例如修改受攻击者的个人音信。然则,由于浏览器同源策略的限制,在第二方“恶意网址”不能读取服务器重临的新闻。也便是说,攻击者只好捣捣乱,不过她依旧赢得不到受攻击者的机灵音信的(无XSS注入的前提下)。可是,固然服务器上某些请求使用了JSONP再次回到用户数据,总之,在第二方,或许别的方网址都能胜利的拿走到。关于CS兰德KugaF/XS哈弗F攻击,就说起此处,具体实现格局就不举办了。

  除了CSLacrosseF/XSTiguanF攻击外,其它利用JSONP的网址(相对于陈设JSONP的服务器)也或者有安全性难题。
因为,通过地点的试行,大家看看了,通过JSONP请求远程服务器后,重返的是3个在本网址即刻施行的函数。也便是那么些剧本直接被注入到当前页面了。如若远端网址中存在注入漏洞,那么结果由此可见了。为了防止那样的事体时有爆发,能够行使 JSON-P
严苛安全子集
使浏览器能够对 MIME
种类是“application/json-p”请求做强制拍卖。假诺答应无法被解析为从严的
JSON-P,浏览器能够丢出1个错误或忽略任何回应。关于安全性的标题先提起这里,安全题材永远是多少个矛与盾的题材,由此可见,在互连网上,未有相对的平安。假如再展开下去又会引出一群东西,所以明天就先不说了。至于何以幸免JSONP简单遭遇的CS卡宴F/XSSportageF攻击,作者认为最简便有效的情势正是对此灵动消息不要采纳JSONP,因为也尚无实际蒙受过,不知底如何越来越好的消除方案。前天就到这里了,希望对我们有用~

相关文章

网站地图xml地图