网络请求之jsonp封装

2023-04-27,,

  首先介绍下jsonp原理

    浏览器因为同源策略的限制,在不同源的服务器通过我们传统axios是不能直接用来请求数据的(忽略代理),而src标签则不受同源策略的影响,所以我们需要动态的创建带有src的标签让其进行数据的请求,这就是jsonp的原理,在src的URL地址末尾拼接上一个回调函数,用来接受服务器传回来的数据

前端jsonp的封装展示

   //封装一个jsonp请求的函数
function query(opt) {
let str = ""
for (let key in opt) {
str += key + "=" + opt[key] + "&"
}
return str
}
//设置默认回调函数的名字
const defaultOptions = {
callbackName: "callback"
}
function jsonp(url, opt, options = defaultOptions) {
//参数解析 URL为访问的接口 opt为传播的数据 option 为接受参数的回调函数
return new Promise((resolve, reject) => {
//判断下这个?是不是存在
let index = url.indexOf("?");
url += index != -1 ? query(opt) : "?" + query(opt);
url = url + `${options.callbackName}=${options.callbackName}`;
//首先创造一个标签 带有src的
const scriptDom = document.createElement("script");
//设置其src属性
scriptDom.setAttribute("src", url);
//在window系统上创建一个回调函数用来接受数据
window[options.callbackName] = (res) => {
//在接受到了参数动态删除这个script节点和window上面的方法
delete window[options.callbackName];
document.body.removeChild(scriptDom)
//接受成功后调用resolve
if (res) {
resolve(res)
} else {
reject("服务器暂没有获取到数据")
}
}
//动态创建script标记,错误的监听
scriptDom.addEventListener('error', () => {
delete window['jsonpCallback'];
document.body.removeChild(script);
reject('服务器加载失败!');
});
document.body.append(scriptDom)
})
}

调用方式

 <script>
// jsonp("http://localhost:7001/api", {
// user: "zhangsan",
// age: "18"
// }).then(res=>{
// console.log(res);
// }).catch(err=>{
// console.log((err,"失败"))
// }) jsonp(" http://localhost:3000/api", {
user: "zhangsan",
age: "18"
}).then(res => {
console.log(res);
}).catch(err => {
console.log((err, "失败"))
})
</script>

后端我们使用express和egg两款框架分别实现了接口的使用

express的代码展示

 const url = require("url")

 router.get("/api", (req, res, next) => {
//将script标签的src的URL请求转成对象
const opj = url.parse(req.url, true).query;
//然后原理就是调用这个回调函数来进行传参
let {
callback
} = opj;
//如果这个回调函数存在证明是jsonp请求
if (callback) {
let resault = JSON.stringify({
code: 1,
msg: "express框架传回去的参数"
});
res.send(`${callback}(${resault})`)
}
})

egg框架就不需要这么麻烦了 利用中间件可以直接出来

router.js代码
module.exports=app=>{
const {router,controller}=app;
const jsonp = app.jsonp();
router.get("/api",jsonp,controller.index.api) //注意不要写成下面这种
// const {jsonp}=app;
// router.get("/api",jsonp(),controller.index.api)
} controller/index 代码
const {Controller}=require("egg"); class Index extends Controller{
api(ctx){
//直接利用body返回就会传到jsonp的回调函数里面
ctx.body={
code:11,
type:"egg返回的jsonp请求"
}
}
} module.exports=Index;

本文GitHup地址  https://github.com/qiang-chen/cross-domain

网络求之jsonp封装的相关教程结束。

《网络请求之jsonp封装.doc》

下载本文的Word格式文档,以方便收藏与打印。