每天做个总结吧,坚持就是胜利!
/**
@date 2021-05-24
@description JSONP原理及实现
*/
壹(序)
JSONP(JSON with Padding),是一种解决跨域的方法,兼容性好,但是只能处理GET请求;其原理是利用HTML的script标签没有跨域限制来解决跨域。 需注意一下几点:
- 前端的回调函数名,需要与后端匹配,所以最好是前端传入函数名,后端基于此名进行处理;
- 后端返回的是一个字符串,前端在数据返回后执行回调;
- 回调需要绑定在window上,因为script标签最后的作用域是window;
贰(前端实现)
const jsonpGet = (url, params, cbName, cb) => {
const container = document.getElementsByTagName('head')[0];
const requestEle = document.createElement('script');
requestEle.src = `${url}?${parmaFormatter(params)}&callback=${cbName}`;
container.appendChild(requestEle);
window[cbName] = function (data) {
cb && cb(data);
container.removeChild(requestEle);
delete window[cbName];
};
requestEle.onerror = () => {
window[cbName] = function () {
cb && cb('has error');
};
container.removeChild(requestEle);
delete window[cbName];
};
};
const parmaFormatter = (params) => {
const keys = Object.keys(params);
return keys.reduce((acc, cur, index) => {
if (index === keys.length - 1) {
return (acc += `${cur}=${params[cur]}`);
} else {
return (acc += `${cur}=${params[cur]}&`);
}
}, '');
};
叁(使用)
jsonpGet('http://localhost:3000', { a: 1, b: 2 }, 'jsonp_test', (res) => {
console.log(res);
});
肆(引申)
实现Promise版本:
const jsonpGet = (url, params, cbName) => {
const container = document.getElementsByTagName('head')[0];
const requestEle = document.createElement('script');
requestEle.src = `${url}?${parmaFormatter(params)}&callback=${cbName}`;
container.appendChild(requestEle);
return new Promise((resolve, reject) => {
window[cbName] = function (data) {
resolve(data);
container.removeChild(requestEle);
delete window[cbName];
};
requestEle.onerror = () => {
window[cbName] = function () {
reject('has error');
};
container.removeChild(requestEle);
delete window[cbName];
};
});
};
jsonpGet('http://localhost:3000', { a: 1, b: 2 }, 'jsonp_test').then(
(res) => {
console.log(res);
}
);