当我们利用XMLHttpRequest对象从本地服务器获取数据时是可以的。
假设我们使用的数据格式为JSON(JavaScript Object Notation),并且我们在本地服务器上部署了一个样本数据data.json:
好了,有了数据,我们试着编写一个简单的页面文件来获取该数据:(该页面文件和data.json位于同一目录下)
页面确实返回了我们从本地服务器获取的数据,我们对其进行了解析。(我们从XMLHttpRequest对象的属性responseText是json字符串,如果需要将其封装成对象,可以使用JSON.parse方法,如果想将对象字符串化,可以使用parse的对称方法JSON.stringnify。)
现在Web Services很流行,它们可以为我们提供需要的数据,比如实时天气信息,比如公交信息,比如其它用户感兴趣的内容。
好了,Twitter为我们提供了一个数据源URL: http://search.twitter.com/search.json?q=hfhtml5 (有些地方需要翻墙。需要的密我)
其实它的内容和data.json文件一样:
现在我们来修改一下页面文件,我们使用外部服务器(相对本地服务器而言)来获取数据:
其实只需要修改open方法的第二个参数url:
重新加载该页面:
咦?页面怎么是空白的。到底怎么回事呢?如果你用的是Google Chrome浏览器的话,可以借助自带的JavaScript控制台(Ctrl+Shift+J)查看哪里出错了。
原因找到了,因为XMLHttpRequest对象不允许跨服务器发送请求,因此该请求被拒绝,外部服务器根本就不知道有请求发送给它。这属于一个跨域安全问题(Cross-Domain Security Issues)。
那么该怎么办呢?既然XMLHttpRequest因为考虑到安全性不允许发送请求到外部服务器,只好寻找其它的办法。
想必大家看过文章标题的都应该猜出,我们可以使用JSONP ( JSON with Padding)。
在讲JSONP之前,先看看几个和JS有关的简单例子:
http://wickedlysmart.com/hfhtml5/chapter6/dog.js 这个URL(无需翻墙)返回的是一个JS文件,它的内容很简单,就是
alert("woof");我们编写一个简单的本地服务器页面来加载该JS文件。
在body标签内部添加了一个script标签,该标签的src属性指向了外部服务器的js文件。
访问该页面后:
这说明了什么?说明了通过加载外部服务器的js文件,可以调用本地浏览器的内置对象的方法(比如window.alert方法)
再继续:
http://wickedlysmart.com/hfhtml5/chapter6/dog2.js 该js文件的内容是:
animalSays("dog", "woof");怎么让该方法被调用呢?我们可以在本地页面创建该函数:
我们增加了一个自定义函数animalSays,该函数接受两个参数,一个是动物名字,一个是动物叫声,另外我们把script标签的属性也修改成另外一个文件。
试着刷新下页面:
看到效果了吧!
好了,有了以上的基础,我们就可以实现从外部服务器获取我们需要的数据了。
只要在外部服务器中生成json数据格式,然后传递给指定的函数即可。
比如:http://wickedlysmart.com/hfhtml5/chapter6/dog3.js 它的内容是
var animal = { "type": "dog", "sound": "woof" }; animalSays(animal);
我们想要得到该外部服务器上的数据,于是编写了该页面文件:
这里传递的是animal对象,该对象包含type和sound属性。(记得修改script标签的属性值)
刷新下页面:
哈哈,看到了吧,外部服务器端的数据就这样轻松的获取到了。
有个问题,外部服务器怎么知道我们本地服务器页面的函数名呢?
我们可以通过URL来指定:
http://search.twitter.com/search.json?q=hfhtml5&callback=myCallback
我们可以指定callback的值来告诉外部服务器本地页面的函数名字。
看到没有,该js的函数名就是URL尾部指定的名字
需要注意的是,使用JSONP存在安全问题,除非我们信任这些网站,比如Twitter,Facebook,google,否则请不要轻易加载它们的数据文件。而XMLHttpRequest则比JSONP更加安全,但是访问外部服务器受限。