使用jQuery与JSONP解决跨域问题

来源:互联网 发布:linux指令大全 完整篇 编辑:程序博客网 时间:2024/05/22 23:51
跨域问题存在实际上源于浏览器的同源策略(same origin policy),简单讲,同源就是要求域名,协议,端口三者都一致;而同源策略就是指页面上的脚本不能访问非同源的资源(包括HTTP响应和Cookie);
很多人会想到一个很熟悉的东西:document.domain
同源策略有点放松的就是:b.a.com上的页面无法通过a.com的同源验证,但是设置b.a.com页面的document.domain 属性为a.com,就可以通过浏览器对a.com的同源检测;但是,document.domain只允许设置成更上级的域名,而不是 其它域名,例如c.com就不行; 提到这里很多人都会想到多级域 名下共享Cookie的路子就是把Cooki设置成上级域名;在Web2.0的时代,这种本质上同域跨级解决方案远远不能满足我们跨域的需求;
我们要讨论的是浏览器端的真正跨域访问,推荐的是目前jQuery中$.ajax()支持get方式的跨域,这其实是采用jsonp的方式来完成的.
先来看jQuery的API中关于$.getJSON()的一个代码示例:
1<script>
2$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?",function(data){
3    $.each(data.items,function(i,item){
4        $("<img/>").attr("src", item.media.m).appendTo("#images");
5        if( i == 3 ) return false;
6    });
7});
8</script>
这种方式其实是$.ajax({..}) api的一种高级封装,有些$.ajax api底层的参数就被封装而不可见了.
针对于上述代码的请求,在服务器端通过 jsoncallback = $_GET["jsoncallback"] 得到jquery端随后要回调的javascript函数名:jsonp1236827957501。
然后 response的内容为一个脚本标签:"jsonp1236827957501("+按请求参数生成的json数组+")";
jquery就会通过回调方法动态加载调用这个js tag:jsonp1236827957501(json数组);
这样就达到了跨域数据交换的目的.
jsonp的最基本的原理是:动态添加一个script标签,而script标签的src属性是没有跨域的限制的。这样说来,这种跨域方式其实与ajax XmlHttpRequest协议无关了.
这样其实"jQuery AJAX跨域问题"就成了个伪命题了,jquery $.ajax方法名有误导人之嫌.
如果设为dataType: 'jsonp', 这个$.ajax方法就和ajax XmlHttpRequest没什么关系了,取而代之的则是JSONP协议.
JSONP是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问
JSONP即JSON with Padding。由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源。如果要进行跨域请求,
我们可以通过使用html的script标记来进行跨域请求,并在响应中返回要执行的script代码,其中可以直接使用JSON传递javascript对象。
这种跨域的通讯方式称为JSONP。
jsonCallback 函数jsonp1236827957501(....): 是浏览器客户端注册的,获取跨域服务器上的json数据后,需要执行的回调函数。
Jsonp原理:
1,首先在客户端注册一个 callback (如:'jsoncallback'), 然后把callback的名字(如:jsonp1236827957501)传给服务器。注意:服务端得到callback的数值后,要用 jsonp1236827957501(......)把将要输出的json内容包括起来,此时,服务器生成 json 数据才能被客户端正确接收。
2,然后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数 'jsoncallback'的值 jsonp1236827957501 .
3,最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。
4,客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时javascript文档数据,作为参数,
传入到了客户端预先定义好的 callback 函数(如上例中jquery $.ajax()方法封装的的success: function (json))里.(动态执行回调函数)
可以说jsonp的方式原理上和“ ”是一致的(QQ空间以及ucenter的通信机制就是大量采用这种方式来实现跨域数据交换的) .JSONP是一种脚本注入(Script Injection)行为,所以也有一定的安全隐患.
注意,jquey是不支持post方式跨域的.
为什么呢?
虽然采用post +动态生成iframe是可以达到post跨域的目的,但这样做是一个比较极端的方式,不建议采用.
也可以说get方式的跨域是合法的,post方式从安全角度上,被认为是不合法的, 万不得已还是不要剑走偏锋..
client端跨域访问的需求看来也引起w3c的注意了,看资料说html5 WebSocket标准支持跨域的数据交换,应该也是一个将来可选的跨域数据交换的解决方案,
下面附上Cmstop中的跨域案例,供大家参考。
前台页面发出AJAX请求,获取一篇文章的统计信息:
1var contentid = 123;
2$(function(){
3            $.getJSON(
4                        'http://app.cmstop.dev/?app=system&controller=content&action=stat&jsoncallback=?&contentid='+contentid,
5                        function(data){
6                                   if(data){
7                                               $('#pv').html(data.pv);
8                                   }
9                        }
10            );
11});
前台应用接收请求并返回需要的数据:
1function stat()
2{
3$contentid = intval($_GET['contentid']);
4 
5$pv = loader::model('pv');
6$data['pv'] =$pv-&gt;get($contentid);
7 
8$comments = loader::model('comments');
9$data['comments'] =$comments-&gt;get($contentid);
10 
11$data['islogin'] = setting('comment','islogin') ? 1 : 0;
12 
13$data = $this-&gt;json-&gt;encode($data);
14echo $_GET['jsoncallback']."($data);";
15}
到这里,我们关于使用jQuery与JSONP解决跨域问题已经可以解决了。当我们以后在项目中再遇到同类问题时,应该不会再毫无头绪了。
来源:PHP教程

原创粉丝点击