Json数据的跨域异步传输与回调

我们知道,由于同源规则的限制,普通的Ajax交互并不能跨域进行。但是有些时候,我们必须对数据进行跨域传输,实际上这些技术现在也应用得比较广泛,很多网站流量统计和分析工具都运用了这种技术,本人之前的文章讲过了这种技术。今天我们要讲的是Json数据的跨域ajax传输和回调。
实际工作中,我们可能会遇到这样的问题,和服务器进行数据交换展示级联下拉菜单,典型的代表是全国各个地区的选择,根据用户的选择的地区,在下一个下拉框展示这个地区下的其它地区(省-市-县(区)),如图:

级联下拉菜单

级联下拉菜单


如果把这些数据全部以数组的方式存放在前端,一个是会加大前台压力,另一个是不利于后期的维护和扩展,所以我们想到了把数据放到服务器,根据用户的需求进行异步加载。
这里有两种情况,第一种是,服务器直接返回数据,另外一种是,客户端对返回的数据进行处理。实际大部分情况,是第二种,例如我们遇到的地区的选择,下面对这个例子进行分析:
前台代码:

<!DOCTYPE HTML>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>Json实现跨域AJAX</title>
</head>
<body>
<script>
	function getCity(p){
		if(p=="") return;
		var json=document.createElement("script");
		json.id="jsondata";
		json.src="http://www.test.com/getCity.php?provice="+p+"&callback=callback";
		document.body.appendChild(json);
	}
	function callback(data){
		var city=document.getElementById("city");
		var cityvar="";
		for(var i in data){
			cityvar+="<option>"+data[i]+"</option>";
		}
		city.removeAttribute("disabled");
		city.innerHTML=cityvar;
		document.body.removeChild(document.getElementById('jsondata'));
	}
</script>
	<select id="provice" onchange="getCity(this.options[this.selectedIndex].value)">
		<option value="">请选择</option>
		<option value="hunan">湖南</option>
		<option value="henan">河南</option>
		<option value="shanghai">上海</option>
	</select>
	<select id="city" disabled="disabled">
	</select>
</body>
</html>

后端代码

<?php
header("Content-Type:text/javascript");
$provice=$_GET["provice"];
$callback=$_GET['callback'];

$area["henan"]='["郑州","开封","洛阳","平顶山","安阳","鹤壁","新乡","焦作","濮阳","许昌","三门峡"]';
$area["hunan"]='["长沙","常德","岳阳","浏阳","郴州","益阳","怀化","湘潭","株洲","湘西自治区"]';
$area["shanghai"]='["浦东新区","黄浦区","卢湾区","徐汇区","长宁区","静安区","普陀区","闸北区","虹口区"]';

echo $callback."($area[$provice])";
?>

原理很简单,当本地的数据更改时,在文档之后插入一个script标签并把相应数据传到服务器上,由于回调函数已经被定义,服务器返回的脚本内容就行马上被执行。我们能注意到,因为浏览器对脚本的引用并没有同域的限制,所以这些请求是能跨域传播的,非常方便后期的扩展。

另外需要注意的是,包涵回调函数的传输非常容易引发XSS,要注意防范。另外,上面的代码还有很多可以优化的地方,为了节省带宽和请求,前台最好做一下数据缓存。

发表回复

评论列表:

Hito
Hito
谢谢你的肯定!@bajie
回复此留言
bajie
bajie
不错的网站,界面虽然不好看,内容都是干货! 谢谢分享
回复此留言