JSONP的原理
JSONP
即是JSON with padding
(填充式JSON
或参数式JSON
)的简写。是由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的JSON
数据。
http://freeapi.com/json/?callback=handleResponse
handleResponse({name: 'JavaScript'})
如上就是通过指定回调函数handleResponse
,当服务器返回相应handleResponse({name: 'JavaScript'})
时作为JavaScript
代码会立即执行。简言之JSONP
是通过动态<script>
元素来使用的,使用时为src
属性指定一个跨域URL
。而<sript>
元素可以不受限制地从其他域加载资源。因为JSONP
是有效的JavaScript
代码,所以在请求完成后,即在JSONP
响应加载到页面中以后,就会立即执行。
function jsonpAction (ctx, res) {
res.body = `${ctx.params.callback}({"name": "JavaScript"})`
}
JSONP的实现
JSONP
是通过动态<script>
元素来使用的,如下所示。
(function (global) {
let cbId = 0
function jsonp (options) {
const {url, callback} = options
if (!url) {
throw new Error(`url is missing`)
}
if (typeof callback !== 'function') {
throw new Error(`callback must be function`)}
}
const cbName = `jsonpCb${cbId++}`
const params = []
for (const [key, value] of Object.entries({...options, callback: cbName})) {
params.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
}
const scriptEle = document.createElement('script')
scriptEle.src = (!~url.indexOf('?') ? `${url}?` : `${url}&`) + `${params.join('&')}`
global[cbName] = function (res) {
callback(res)
document.head.removeChild(scriptEle)
delete global[cbName]
}
scriptEle.onerror = function () {
document.head.removeChild(scriptEle)
delete global[cbName]
}
scriptEle.type = "text/javascript"
document.head.insertBefore(scriptEle, document.head.children[0])
}
global.jsonp = jsonp
})(this)