欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

js跨域问题解决

程序员文章站 2022-03-03 17:36:48
...

 

这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据。只要协议、域名、端口有任何一个不同,都被当作是不同的域。

下表给出了相对http://store.company.com/dir/page.html同源检测的结果:

 

URL 说明 是否允许通信
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>