[聚合文章] JSONP 实现

JSONP 2016-04-22 13 阅读
function editAtGithub(isRaw){ var url_parts = document.location.pathname.split('/'); var postname = url_parts[url_parts.length - 2]; if(url_parts.length == 3){ // is a page(wiki about etc) postname = postname + '/index.org'; }else{ postname = '_posts/' + postname + '.org'; } var url = 'https://github.com/CodeFalling/codefalling.com/tree/source/source/' + postname; if(isRaw) url = 'https://raw.githubusercontent.com/CodeFalling/codefalling.com/source/source/' + postname; window.open(url); }

JSONP

JSONP 是用来解决前端 ajax 的跨域问题,例如从 codefalling.comjss.weibo.com 获取数据时,如果使用普通 ajax ,会被浏览器因为安全因素拦截。而通过 <script> 标签加载其他域的 js 是没有跨域问题的,于是便有了 JSONP 这种 hack 手段。

由于 JQuery 等库将其封装成和普通 ajax 形式一样的请求,所以常常有人误解,其实其原理和普通请求完全不同。本文通过简单的实现来解释一下这种 hack 的原理。

JQuery

首先看一个在 JQuery 中使用 JSONP 最简单的例子。

$.ajax({
url: "http://s.weibo.com/ajax/jsonp/suggestion?_cb=callback_fun&key=test",
dataType: 'jsonp',
jsonpCallback: 'callback_fun',
success: function(data){
console.log(JSON.stringify(data))
}
})

这里用的是新浪微博提供的一个 JSONP API 的范例,执行后可以看到控制台输出了[ 1 ]

{"code":100000,"msg":"","data":["特事特办","TEST"]}

看起来似乎和普通的 ajax 无异,但其实是 JQuery 的封装所致,我们可以手动访问 s.weibo.com/ajax/jsonp/suggestion?_cb=callback_func&amp;key=test ,得到

try {
window.callback_func & callback_func({
"code": 100000,
"msg": "",
"data": ["\u7279\u4e8b\u7279\u529e", "TEST"]
});
} catch (e) {}

看起来并不是一个 JSON 文件,反倒像 JS

原理

JSONP 实际上是通过提前定义好 callback 函数(上面的代码里是 callback_func ),再通过追加一个 <script> 标签到文档上, src 指向 JSONP 请求的目标。由于 <script> 标签不受跨域的影响,我们讲 JSONP 作为一个 JavaScript 文件加载 ,然后 JSONP (或者说上面的 js 代码)得到执行。将其要传递的数组通过调用 callback 的方法传递给 JS

实现

看起来可能比较混乱,但是代码有时候比文字更为直观,我们可以尝试自己实现一个简单的 JSONP 封装。

function jsonp_ajax(url, callback_name, success){
// 提前准备好回调函数给 script 标签调用
var callback_func = function(data){
success(data)
}
window[callback_name] = callback_func

// 插入 script 标签
var script = document.createElement('script')
script.setAttribute('src', url)
document.body.appendChild(script)
}

jsonp_ajax('http://s.weibo.com/ajax/jsonp/suggestion?_cb=callback&key=test',
'callback',
function(data){
console.log(data)
})

可以达到和上面的一样的效果。

Footnotes:

1

代码可以在 Create a New Pen 直接测试

Edit Me at Github-Org Source- Last Updated 2016-04-23 Sat 13:03.

Render by hexo-renderer-org with Emacs 24.5.1 ( Org mode 8.2.10)

注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。