JSONP(JSON with Padding)
Overview
同源策略(协议、域名、端口相同),它是由Netscape提出的一个著名的安全策略,现在所有的可支持javascript的浏览器都会使用这个策略。
跨域的安全限制都是指浏览器端来说的.服务器端是不存在跨域安全限制的。
在HTML文档中能够发起HTTP请求的元素有 <link>
请求css、<script>
请求脚本、<iframe
>请求HTML文档、<img>
请求图片、<a>
链接、<form>
的GET和POST请求、<object>
其他媒体资源、<source>
音频和视频资源等传统HTTP资源请求(大多是GET请求),都可以实现跨域。
而对于AJAX是通过 XMLHttpRequest进行通信的,请求头部多了 X-Requested-With:XMLHttpRequest 字段,无法跨域。
JSONP
是非官方的一种数据传输协议。解决浏览器“跨源资源共享”的一种方案。
本质是采用<script>
的跨域访问资源的特性来解决跨源问题的, 所以JSOP并不是AJAX请求,就是一个传统的HTTP请求
How
JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,而数据就是传入回调函数中的JSON数据。如一个JSOP的URL请求:
http://example.com/json/?callback=handleResponse
jsonp动态创建的节点确实是需要删除的。jQuery在节点onload/complete时,删除节点
注意,jquey是不支持post方式跨域的. 虽然采用post +动态生成iframe是可以达到post跨域的目的(有位js牛人就是这样把jquery1.2.5 打patch的),但这样做是一个比较极端的方式,不建议采用. 也可以说get方式的跨域是合法的,post方式从安全角度上,被认为是不合法的, 万不得已还是不要剑走偏锋..
可以利用Flash+js的方式, 前提是客户端必须有flash,并且在服务端的根目录下放置crossdomain.xml文件
jQuery的跨域写法
Ajax() 方法
指定dataType为jsonp或scrip
// Using YQL and JSONP
$.ajax({
url: "http://query.yahooapis.com/v1/public/yql",
// The name of the callback parameter, as specified by the YQL service
jsonp: "callback",
// Tell jQuery we're expecting JSONP
dataType: "jsonp",
// Tell YQL what we want and that we want JSON
data: {
q: "select title,abstract,url from search.news where query=\"cat\"",
format: "json"
},
// Work with the response
success: function( response ) {
console.log( response ); // server response
}
});
getScript() 方法
getScript() 方法通过 HTTP GET 请求载入并执行 JavaScript 文件。注: jQuery1.2后才支持跨域调用 JavaScript 文件
getJSON() 方法
通过 HTTP GET 请求载入 JSON 数据。
Advance
- 使用HTML5的window.postMessage方法跨域
window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法
清除动态加入的script节点
用jquery的话,用$.getJSON()或$.ajax()方法在发生错误时可以用error回调函数来捕获错误,前端对用户进行提示。另一个方法,设定一段延时,超过设定时间无响应的话提示用户稍后重试等等。
JSONP是需要动态创建script标签的,我们需不需要处理这些script元素?
还有一个需要考虑的就是,很多框架/库在实现jsonp时,一般都会生成一个uuid,比如jQuery19109801354627124965_1398582826844,然后将它挂载到window上,用以包装用户的callback,比如:
window['jQuery19109801354627124965_1398582826844'] = function() {
// ...
callback();
// ...
}
这些挂载到window上的callback也是需要释放的。
清除标签后浏览器仅仅是移除这个节点而已,并没有对节点内的JS进行垃圾回收。即使script标签移除了,元素的属性还是可以取到的,比如src属性。要回收这段JS可以手动清除script元素所有属性:
var jsonp = document.getElementById('myJson'); //取得script元素
for (var prop in jsonp) {
delete jsonp[prop];
}
以Chrome 控制台为例,每次垃圾回收都会触发 GC event Chrome Developer Tools之Timeline面板, 浏览器自动垃圾回收(一般发生在unload、inactive tab或者产生了太多垃圾不得不gc时),区别于内存泄漏(memory leak)。