JSONP其实跟ajax都可以跨域进行数据请求,它们之间却没什么联系,ajax的核心是通过XmlHttpRequest获取非本页内容,而JSONP的核心则是动态添加 script 标签来调用服务器提供的js脚本。
JSONP跟JSON只有一个字母之差,完全是两种东西,JSON是一种数据传递的格式,JSONP是开发人员创造出来的一种数据跨域方法。
<script> function handler(data){ alert("本地函数,跨域的remote.js在调用我,并提供给我data数据:" + data.message); } </script>
然后加载远程的js文件,这个文件只做了调用handle的动作,并传入了参数:
<script src="http://lefeier.net/ext/js_test/remote.js"></script>
//romote.js的内容:
//handler({"message" : "我是远程js带来的消息"});
这就跨域成功了,但是这样做会有一个明显的问题,远程的js调用本地的函数,它不可能只服务于一个页面的函数,它会服务很多的对象,这些对象的函数都不相同,问题是怎样让远程的JS知道本地的函数是什么?
于是那些开发者想到,只要传过去参数让服务器知道我本地需要调用的函数名就行,服务器按照调用者的需求生成js并响应就行。
JSONP的核心手段
<script> function handlerResponse(data) { alert("我的IP是:" + data.ip); } var script = document.createElement("script"); // URL地址返回的是一段javascript代码 script.src = "http://freegeoip.net/json/?callback=handlerResponse"; document.body.insertBefore(script,document.body.firstChild); </script>
执行成功
它利用在请求中增加callback的方法告诉服务器我本地的要调用的函数名是handlerResponse, 请把结果传入这个函数中进行调用。
这段代码返回的函数调用是:
传给handlerResponse的是一段json格式的数据, 包含我的IP,国家,代码,经纬度,时区等信息。
然而JQuery把JSONP封装在ajax中了,这里需要明白的是JSONP和ajax的XmlHttpRequest有本质上的区别,实际上利用了拥有跨域获取资源的能力的标签script,比如img,iframe,script 这些带有src属性的标签天生就有获取跨域资源的能力; 通过在请求中定义回调函数的名字,和传入回调函数的json数据,实现跨域获取信息。
JSONP的缺点:
- JSONP有不安全的风险,在使用不是自己维护的web服务器需要保证它的安全;
- JSONP无法使用POST提交;
- JSONP在确定请求失败不容易。
HTML5给script元素增加了onerror属性并不是所有浏览器都支持(IE6~8与opera11都不支持,safari,chrome,firefox,ie9支持),开发人员被迫使用倒计时的手段来检测是否得到了响应,但这样不尽人意。
“检测的时机只有这四个 onload,ontimeout,onerror,因此需要检测浏览器是否支持onerror事件。,但opera是无法通过编程方式检测opera的支持情况”
当然还有一些其他的手段来检测: JSONP的回调函数总是在script的onload事件(IE的onreadystatechange)之前就被调用,因此在回调执行之时,为script标签增加一个属性,然后等到onload发生的时候,检查有没有这个属性,来以此判定是否请求成功,具体请参见:http://www.cnblogs.com/rubylouvre/archive/2011/02/13/1953087.html