迫不及待?

您可以下载源代码 或者直接
在线使用

背景

曾经写过一个自动抓取火车站经纬度的工具。前些天又有人有批量抓取地址经纬度的需求,就借这个帮忙的机会学习了一下bootstrapjquery更深的了解了github

实现

Geocoding API

Geocoding API是百度地图WebAPI的一款地址与经纬度相互转换的api。使用它只需注册百度开发账号并申请一个key。具体使用方法知识一个GET请求,各种字段描述的很清楚。我就不多说啦

请求顺序

因为没有性能要求,而强迫症又要求我最后结果的顺序与用户输入的地址顺序保持一致。所以我用到了async.eachSeries来迭代处理地址数组。这里也可以用async.eachasync.each会并发请求,速度更快但返回的先后顺序不能保证。为了保证结果顺序与用户输入的地址顺序相同我使用了async.eachSeries

JSONP解决跨域

对前端了解不多,本来以为直接$.get(url)就可以解决问题。没想到遇到了跨域请求的限制

什么是跨域?

JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。简单地理解就是因为JavaScript同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象。

什么是JSONP

维基百科的定义是:JSONP(JSON with Padding)是资料格式 JSON 的一种“使用模式”,可以让网页从别的网域要资料。

JSONP也叫填充式JSON,是应用JSON的一种新方法,只不过是被包含在函数调用中的JSON,例如:
callback({"name","trigkit4"});
JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,而数据就是传入回调函数中的JSON数据。

在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的。但是,在页面上引入不同域上的js脚本文件却是可以的,jsonp正是利用这个特性来实现的。 例如:

1
2
3
4
5
6
<script type="text/javascript">
function dosomething(jsondata){
//处理获得的json数据
}
</script>
<script src="http://example.com/data.php?callback=dosomething"></script>

js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入。所以jsonp是需要服务器端的页面进行相应的配合的。

1
2
3
4
5
<?php
$callback = $_GET['callback'];//得到回调函数名
$data = array('a','b','c');//要返回的数据
echo $callback.'('.json_encode($data).')';//输出
?>

最终,输出结果为:dosomething(['a','b','c']);

如果你的页面使用jquery,那么通过它封装的方法就能很方便的来进行jsonp操作了。

1
2
3
4
5
<script type="text/javascript">
$.getJSON('http://example.com/data.php?callback=?,function(jsondata)'){
//处理获得的json数据
});
</script>

jquery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。$.getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用jsonp的回调函数。

JSONP的优缺点

  • JSONP的优点是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果。

  • JSONP的缺点则是:它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。

本项目使用JSONP

Geocoding API很友好的提供了JSONP功能,只要在url中增加callback参数即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var convertAndShow = function (locationArr){ 

async.eachSeries(locationArr , function(location , cb){//循环处理每个地址 1
location = $.trim(location);//去掉空字符
if(!location) return cb();
var url = getUrl(location);//拼接api url
$.getJSON(url, function(data){ //jsonp请求 2
//alert(data.status);
if(data.status === 0 && data.result){
//显示
showResult(location,data.result);//成功
}else{
showError(location ,data.status , data.msg)//有错误
}
cb();//执行下一个地址
});
});

}

var getUrl = function(location){
return 'http://api.map.baidu.com/geocoder/v2/?address='+location+'&output=json&ak=gQsCAgCrWsuN99ggSIjGn5nO&callback=?'
}