标签的src属性不受浏览器跨域的限制
- 要点
- 创建script标签
- 前端一个全局函数
- 服务端返回前端全局函数的调用
function jsonp (url) {
/*声明一个唯一的回调函数并挂载到全局上
*创建一个script标签地址 指向 请求服务器 将回调函数名作参数带到服务器
*服务器拿到回调名称 并返回前端 该回调的调用 把返回结果当作参数传入
*/
let script = document.createElement('script')
let uniqueName = `jsonpCallback${new Date().getTime()}`
script.src = `url${url.indexOf('?') > -1 ? '&': '?'}callback=${uniqueName}`
document.body.appendChild(script)
window[uniqueName] = (res) => {
cb && cb(res)
document.body.removeChild(script)
delete window[uniqueName]
}
}
// 调用
jsonp('getList', (res) => {
console.log(res)
})
// 服务器端
1. 获取参数, 拿到回调函数名称
2. 返回参数名的前端回调的调用 并 把要返回的参数作为实参调用
/*弊端 - 只支持get请求,并且不安全,需要服务器支持*/
function jsonp ({url, query}) {
let script = document.createElement("script");
let cb = `jsonpCallBack${new Date().getTime()}${Math.floor(Math.random(5)*100000)}`
let params = {...query, cb}
let arr = []
for (let key in params) {
arr.push(`${key}=${params[key]}`)
}
script.src = `${url}?${arr.join("&")}`
document.body.appendChild(script)
return new Promise((resolve, rej) => {
window[cb] = function (res) {
resolve(res)
document.body.removeChild(script)
delete window[cb]
}
})
}
jsonp({
url:'/getList',
query: {name: 'ys',age: 19}
}).then((res) => {
console.log(res)
})