前言:

     
前几日,无意间看到好某个文件夹下暴发个JSONP的物。逐渐回忆起,这么些事物是前想写的一个demo,也非知道是多长时间从前了,不过非晓得怎么的,给忘掉这边了。那么,就趁这些时机把她成功吧,其实为下是一个demo,就是一个不怎么尝试,固然,网上也就发众多有关JSONP的作品和例子了,但是多少东西看好粗略,不亲自尝试一下毕竟觉得不扎实。我前几日干什么而试,一方面为是时以网上来看稍微网站要跨域拿到数量,然则当前温馨开的型遭到还要尚未有关要求,于是丰盛奇怪,于是就暴发了即篇稿子,于是……这便先河本次操演吧。

一 什么是JSONP

   JSONP全称:JSON with Padding

  
看到名字,好像说,JSONP是JSON的呦?或许有人会问,什么是JSON呢?若是来同学还无清楚JSON,可以先行夺询问下JSON,然后再一次持续本文的读书或会再度好。简单的游说,JSON是同一栽多少沟通格式,在大家透过ajax技术获取数据的上,可以坐XML或者JSON这样的格式举办传递。ajax虽然好用,不过也发生遭遇困难的时候,比如你需要跨域获取数据。这多少个时段,普通的ajax获取形式就是不顶容易了,这时候,JSONP就好协理了。那里还添下前提到跨域问题,跨域其实简单的游说不怕是,比如你协调写了一个网站将其部署到域名是www.a.com的服务器上,然后你得毫无压力的运ajax请求www.a.com/users.json 
的数额。 可是,当要而通过平日ajax格局呼吁www.b.com域名下之www.b.com/users.json的数目平时,就无这好了,在前面的略尝试被,可以望这等同动静。既然用普通的ajax技术不可以形成,那么JSONP又是什么样做到的也罢?

二 JSONP的基本原理

   JSONP可以兑现跨域,这假诺归功给强大的<script></script>元素标签。除了大家晤面当其中间写js代码外,也时常会以网站面临经它们的src属性引入外部js文件,关键就于是,大家的引入的js文件也足以免是同一个域下的。那么我们啊就是得以原需要取得之JSON数据勾勒及js文件中去,然后再拿到。可是,不幸之事情到底发生了,当我们把同截JSON格式的数额,例如:

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

写入js文件,然后经过<script>元素引入后,却报错了。原因是<script>标签元素仍旧颇老实的,因为它们便是背负实施js的,所以你相当JSON格式的多少它为会大刀阔斧的当js代码去实施,而老大数据从不切合js语法,于是便颇正剧的错了。但那出错,同样也带来吃了大家答案,不是为?既然无抱js语法不行,大家打个符合的非就可以了。这里一种植常用之章程即使是返一个函数callback({“id”
: “1”,”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中吗未曾接纳第三在的框架(不了后来稍微后悔了,多写了不少……)。

率先要效法七只地段,因为我当windows下,所以可以改host文件,添加

图片 1

些微只域名映射到本机回送地址127.0.0.1。然后开端写代码:

创造两单Node.js的用,一个凡是appA.js,一个appB.js。首先,我们品尝通过平常ajax获取同域的数目:

appB.js代码:

 

图片 2图片 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...');

 图片 4

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

图片 5

此间来只按钮获取自我的粉丝,ajax就起url:”http://www.b.com:9099/followers.json该源拿到数量,这么些数量以代码中,我们呢足以找到,就是

图片 6

 当点击获取后,如下:

图片 7

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

图片 8

修改appB.js中ajax请求的URL为http://www.a.com:8088/followers.json ,现在凡是appB服务器本身是http://www.b.com:9099/index 而去请求www.a.com产之多少===》启动它

图片 9

接下来点击获取粉丝按钮会发现:

图片 10

 真的从未有过取到数据。。。。。。

双重尝试JSONP的计,大家修改appB.js如下:

图片 11图片 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...');

 注意看48执行及51实施,48实施定义了回调函数,51实践通过<script>标签,请求不同域的数量,其中传递参数callback=getFollowers

下一场修改appA.js如下:

图片 13图片 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...');

 第10举办-23举行,我们处理了传递的参数,并拿数据填到函数参数,并发送至请求者这边。再度运行多少个次,刷新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会默认随机大成一个名号:

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

 

五 JSONP可能惹的安全性问题

  由JSONP可能滋生的防城港问题关键是可能会面碰到CSRF/XSRF的攻击,而使容易受到该攻击的吧巧是上文中一向干的JSONP的特色–可以跨源访问资源。普通的CSRF/XSRF攻击,仅仅可能应用吃攻击用户,骗取服务器的相信,这样尽管足以套受攻击者对服务器举行一些有损伤之呼吁,例如修改被攻击者的个人新闻。但是,由于浏览器同源策略的限定,在第三方“恶意网站”不可以读取服务器重返的信。也就是说,攻击者只好捣捣乱,但是他要得到不至于攻击者的机智音信的(无XSS注入的前提下)。但是,倘使服务器上某请求使用了JSONP重返用户数据,显而易见,在第三方,或者其他方网站都可以无往不利的得到。关于CSRF/XSRF攻击,就说到此处,具体实现模式尽管未开展了。

  除了CSRF/XSRF攻击外,此外利用JSONP的网站(相对于部署JSONP的服务器)也说不定来安全性问题。
因为,通过地点的试行,我们看了,通过JSONP请求远程服务器后,重回的凡一个在本网站顿时执行之函数。异常给这本子直接让注入到当前页面了。如果远端网站被是注入漏洞,那么后果可想而知了。为了以防万一这样的工作时有暴发,可以拔取 JSON-P
严苛安子集
而浏览器可本着 MIME
系列是“application/json-p”请求做强制拍卖。倘诺答应不克吃分析为严酷的
JSON-P,浏览器可吐弃出一个错误或疏忽任何回应。关于安全性的题目先行说及此,安全题材永远是一个矛与盾的题材,不言而喻,在互联网及,没有相对的安全。假若又开展下去又会引出一积聚物,所以明天就先不说了。至于怎么防JSONP容易受到的CSRF/XSRF攻击,笔者觉得最简易可行的艺术就是对灵动信息不要用JSONP,因为也绝非实际遭遇了,不知晓呀还好之解决方案。后天就是到这里了,希望对咱们有用~

相关文章

网站地图xml地图