一、Jsonp的特点
1、Jsonp是解决跨域的方式之一。
2、Jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本,所以兼容性非常好。
3、Jsonp只支持get请求。
4、Jsonp在调用失败的时候不会返回各种HTTP状态码。
5、在请求完毕后通过调用callback的方式回传结果,将回调方法的权限给了调用方。所以在调用jsonp接口时,需要与被调用方协商好用于callback的参数名字,参数的值为函数名。例如cb=_jsonp1234。cb为双方约定好的参数名,_jsonp1234指定被调用方所要执行的函数名。所以调用方在调用前要保证已方拥有该函数用于接收值。
二、通过Promise封装Jsonp
/*
* 实现对 Jsonp 的封装
* url:请求地址
* params:传递的参数对象
* jsonp:与服务端协商的用于存放函数名字的参数
* */
export default function jsonp({url = "", params = {}, jsonp = "cb"}) {
return new Promise((resolve, reject) => {
// 定义 body 用于接收数据
let body = null;
// 自定义函数的名字
const cbName = "_jsonp" + Math.random().toString(36).substr(2);
// 将jsonp放入params
params[jsonp] = cbName;
// 自定义函数,用于接收值
window[cbName] = function (data) {
body = data;
}
function _handler({type}){
// 删除script标签
document.body.removeChild(script);
// 删除自定义的函数
delete window[cbName];
// 加载完毕并得到数据执行resolve
console.log(1111,body)
if(type === "load" && !body) resolve(body);
// 异常执行 reject
else if(type === "error") reject("加载失败");
}
// 将对象转为urlencoded格式
const urlencoded = Object.keys(params).map(v => v + "=" + params[v]).join("&");
// 将地址url与参数进行拼接。
url += (url.includes("?") ? "&" : "?") + urlencoded;
// 创建 script 标签
const script = document.createElement("script");
script.src = url;
// 加载完毕
script.onload = _handler;
// 加载异常
script.onerror = _handler;
// 指定类型
script.type = 'text/javascript';
// 脚本可用,异步执行
script.async = true;
// 创建好的script放入body.
document.body.appendChild(script);
})
}
三、前端调用通过百度jsonp的接口进行调用测试:
<script type="module">
import jsonp from "./jsonp.js";
// https://www.baidu.com/sugrec?prod=pc&wd=web前端&cb=cb
(async () => {
try {const res = await jsonp({
url: "https://www.baidu.com/sugrec",
params: {
prod: "pc",
wd: "web前端",// 指定关键字
},
jsonp: "cb"
});
console.log(res);
} catch (err) {
console.log(e)
}
})();
</script>