jsonp原理
简单来说,由于浏览器对安全的限制,默认禁止跨域请求,但是对资源(例如图片、js、css)是允许跨域的,所以基于该特性,jsonp即通过动态生成"script"标签来访问跨域接口,同时提供给服务端一个方法名,服务端返回一个调用该方法名的调用方法,参数即为客户端想要的数据。
简单实现
// 引入qs模块序列化请求参数
import qs from 'qs'
/**
* 获取随机的jsonp回调方法名
* @returns {string}
*/
const getRandomFunctionName = () => {
// 固定前缀 + 随机数转成36进制字符串
return '__JSONP__' + Math.random().toString(36).substring(2)
}
/**
* jsonp请求
* @param url 请求地址,推荐使用"//"不加协议类型开始
* @param data 请求参数
* @param ops 附加属性
* @returns {Promise<any>}
*/
export const jsonp = (url = '', data = {}, ops = {}) => {
return new Promise((resolve, reject) => {
// 创建script标签
const script = document.createElement('script')
script.type = 'text/javascript'
// 格式化url,去除末尾多余的 "?" "&"
let src = url.replace(/[&|?]+$/, '')
// jsonp 全局回调函数名
let callback = getRandomFunctionName()
while (window[callback]) {
callback = getRandomFunctionName()
}
// 设置超时
const timeoutId = setTimeout(() => {
window[callback] = () => {
// 删除全局回调函数
try {
delete window[callback]
} catch (e) {
window[callback] = undefined
}
}
// 移除script标签
document.body.removeChild(script)
reject(new Error(`JSONP timeout`))
}, (ops.timeout || 30) * 1000)
// jsonp 全局回调函数
window[callback] = (data = {}) => {
// 清除超时
clearTimeout(timeoutId)
// 删除全局回调函数
try {
delete window[callback]
} catch (e) {
window[callback] = undefined
}
// 移除script标签
document.body.removeChild(script)
resolve(data)
}
// 拼装请求参数,默认服务端接受方法名的属性为"callback",可以在ops里指定
Object.assign(data, {[ops.callback || 'callback']: callback})
// qs 序列化参数、并追加参数
script.src = `${src}${src.indexOf('?') > 0 ? '&' : '?'}${qs.stringify(data, {arrayFormat: ops.arrayFormat || 'repeat'})}`
// jsonp 异常
script.onerror = e => {
// 清除超时
clearTimeout(timeoutId)
const target = e.target || e.srcElement
// 移除script标签
document.body.removeChild(script)
reject(new Error(`JSONP Error: fail to load ${target.src}`))
}
// 挂载script标签
document.body.appendChild(script)
})
}
// jsonp调用
jsonp('//www.xxx.xxx/api/getXxx', {name: 'luyantao', age: '30'}).then((result = {}) => {
console.log(result)
})
复制代码
转载于:https://juejin.im/post/5c481f41f265da612415c1f4