数字营销 · Web开发 · 基础设施

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

通过级联下拉菜单的例子,介绍利用 script 标签实现 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 代码如下:

<?php

header("Content-Type:text/javascript");

$provice = $_GET["provice"];
$callback = $_GET["callback"];

$area["henan"] =
'["郑州","开封","洛阳","平顶山","安阳","鹤壁","新乡","焦作","濮阳","许昌","三门峡"]';

$area["hunan"] =
'["长沙","常德","岳阳","浏阳","郴州","益阳","怀化","湘潭","株洲","湘西自治区"]';

$area["shanghai"] =
'["浦东新区","黄浦区","卢湾区","徐汇区","长宁区","静安区","普陀区","闸北区","虹口区"]';

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

?>

实现原理

原理其实比较简单。

当用户选择省份以后,JavaScript 动态创建一个 script 标签,然后把相应的数据传递给服务器。例如:

http://www.test.com/getCity.php?provice=hunan&callback=callback

服务器收到请求之后,根据省份返回相应的数据。

返回的内容实际上并不是单纯的 JSON,而是一段可以直接执行的 JavaScript:

callback(["长沙","常德","岳阳", ...])

由于前台已经定义好了:

functioncallback(data){
...
}

所以浏览器加载服务器返回的脚本之后,就会直接执行这个回调函数。

整个过程可以简单理解成:

选择省份

动态创建 script

跨域请求服务器

服务器返回 callback(JSON)

浏览器执行 callback()

更新城市下拉菜单

这里比较重要的一点就是:

浏览器对 script 标签的加载并没有普通 Ajax 那样的同源限制。

因此,可以通过动态插入 script 标签的方式完成跨域数据请求。

这种方式使用起来比较方便,也比较容易进行扩展。

需要注意的问题

另外还需要注意一点。因为服务器返回的内容中包含回调函数,所以这种传输方式如果处理不当,非常容易引发 XSS 问题,需要特别注意数据的安全处理。

除此之外,上面的代码还有很多可以优化的地方。例如,为了减少重复请求和节省带宽,前台最好对已经获取过的数据进行缓存。

例如第一次选择湖南的时候获取一次:

湖南 → 长沙、常德、岳阳……

之后再次选择湖南,就没有必要再次向服务器请求,可以直接使用之前已经获取的数据。这样可以进一步减少请求数量。

评论0

欢迎分享你的看法,也欢迎补充不同的实践经验。