js跨域问题解决
程序员文章站
2022-03-03 17:36:48
...
这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据。只要协议、域名、端口有任何一个不同,都被当作是不同的域。 下表给出了相对http://store.company.com/dir/page.html同源检测的结果:
http://www.a.com/a.js http://www.a.com/b.js |
同一域名下 | 允许 |
http://www.a.com/lab/a.js http://www.a.com/script/b.js |
同一域名下不同文件夹 | 允许 |
http://www.a.com:8000/a.js http://www.a.com/b.js |
同一域名,不同端口 | 不允许 |
http://www.a.com/a.js https://www.a.com/b.js |
同一域名,不同协议 | 不允许 |
http://www.a.com/a.js http://70.32.92.74/b.js |
域名和域名对应ip | 不允许 |
http://www.a.com/a.js http://script.a.com/b.js |
主域相同,子域不同 | 不允许 |
http://www.a.com/a.js http://a.com/b.js |
同一域名,不同二级域名(同上) | 不允许(cookie这种情况下也不允许访问) |
http://www.cnblogs.com/a.js http://www.a.com/b.js |
不同域名 | 不允许 |
通过jsonp跨域 在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的。但是,在页面上引入不同域上的js脚本文件却是可以的,jsonp正是利用这个特性来实现的。 假定两个应用是同一个ip,只是端口不同,A应用对于8081端口,B应用对于8080端口,A应用访问B应用的数据源。 比如,有个a.html页面,它里面的代码需要利用ajax获取一个不同域上的json数据,假设这个json数据地址是http://192.168.1.100:8080/videobrower/video/manage.do?method=getJsonList,那么a.html中的代码就可以这样: <script> function dosomething(jsondata){ var rows = jsondata; for(var i=0;i<rows.length;i++){ alert('[id:'+rows[i].id+',title:'+rows[i].title+',timelength:'+rows[i].timelength+']'); } } </script> <script src="http://192.168.1.100:8080/videobrower/video/manage.do?method=getJsonList&callback=dosomething"></script> 我们看到获取数据的地址后面还有一个callback参数,按惯例是用这个参数名,但是你用其他的也一样。当然如果获取数据的jsonp地址页面不是你自己能控制的,就得按照提供数据的那一方的规定格式来操作了。 因为是当做一个js文件来引入的,所以http://192.168.1.100:8080/videobrower/video/manage.do?method=getJsonList返回的必须是一个能执行的js文件,所以这个页面的java代码可能是这样的: public class VideoManageAction extends DispatchAction { public ActionForward getJsonList(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { String callback = request.getParameter("callback"); List<Video> videos = new ArrayList<Video>(); videos.add(new Video(78, "喜羊羊与灰太狼全集", 90)); videos.add(new Video(79, "实拍舰载直升东海救援演习", 20)); videos.add(new Video(80, "喀麦隆VS荷兰", 30)); StringBuilder sb = new StringBuilder(); sb.append('['); for (Video video : videos) { sb.append("{"); sb.append("'id':").append(video.getId()).append(','); sb.append("'title':'").append(video.getTitle()).append("',"); sb.append("'timelength':").append(video.getTime()); sb.append("}"); sb.append(','); } sb.deleteCharAt(sb.length() - 1); sb.append(']'); request.setAttribute("json", sb.toString()); request.setAttribute("callback", callback); return mapping.findForward("jsonpresult"); } } jsp页面内容如下:(使用el表达式输出后台传过来的数据) <%@ page language="java" contentType="text/plain; charset=UTF-8" pageEncoding="UTF-8"%>${callback}(${json}) 最终那个页面输出的结果是: dosomething([{'id':78,'title':'喜羊羊与灰太狼全集','timelength':90},{'id':79,'title':'实拍舰载直升东海救援演习','timelength':20},{'id':80,'title':'喀麦隆VS荷兰','timelength':30}]) 所以通过http://192.168.1.100:8080/videobrower/video/manage.do?method=getJsonList&callback=dosomething得到的js文件,就是我们之前定义的dosomething函数,并且它的参数就是我们需要的json数据,这样我们就跨域获得了我们需要的数据。 这样jsonp的原理就很清楚了,通过script标签引入一个js文件,这个js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入。所以jsonp是需要服务器端的页面进行相应的配合的。 知道jsonp跨域的原理后我们就可以用js动态生成script标签来进行跨域操作了,而不用特意的手动的书写那些script标签。如果你的页面使用jquery,那么通过它封装的方法就能很方便的来进行jsonp操作了。 <script type="text/javascript" src="jquery.js"></script> <script> function getJsonList(){ $.getJSON('http://192.168.1.100:8080/videobrower/video/manage.do?method=getJsonList&callback=?',function(jsondata){ var rows = jsondata; for(var i=0;i<rows.length;i++){ alert('[id:'+rows[i].id+',title:'+rows[i].title+',timelength:'+rows[i].timelength+']'); } }); } </script> 原理是一样的,只不过我们不需要手动的插入script标签以及定义回掉函数。jquery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。$.getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用jsonp的回调函数。 jquery对跨域问题的支持:
$.getJSON <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> $.getJSON("http://crossdomain.com/services.php?callback=?", function(result) { for(var i in result) { alert(i+":"+result[i]);//循环输出a:1,b:2,etc. } }); </script>
$.ajax <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> $.ajax({ url:"http://crossdomain.com/services.php", dataType:'jsonp', data:'', jsonp:'callback', success:function(result) { for(var i in result) { alert(i+":"+result[i]);//循环输出a:1,b:2,etc. } }, timeout:3000 }); </script>
$.get <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> $.get('http://crossdomain.com/services.php?callback=?', {name: encodeURIComponent('tester')}, function (json) { for(var i in json) alert(i+":"+json[i]); }, 'jsonp'); </script>