网络请求之jsonp封装

  首先介绍下jsonp原理   

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

前端jsonp的封装展示

 1   //封装一个jsonp请求的函数
 2   function query(opt) {
 3       let str = ""
 4       for (let key in opt) {
 5           str += key + "=" + opt[key] + "&"
 6       }
 7       return str
 8   }
 9   //设置默认回调函数的名字
10   const defaultOptions = {
11       callbackName: "callback"
12   }
16   function jsonp(url, opt, options = defaultOptions) {
17       //参数解析  URL为访问的接口 opt为传播的数据  option 为接受参数的回调函数
18       return new Promise((resolve, reject) => {
19           //判断下这个?是不是存在
20           let index = url.indexOf("?");
21           url += index != -1 ? query(opt) : "?" + query(opt);
22           url = url + `${options.callbackName}=${options.callbackName}`;
23           //首先创造一个标签 带有src的
24           const scriptDom = document.createElement("script");
25           //设置其src属性
26           scriptDom.setAttribute("src", url);
27           //在window系统上创建一个回调函数用来接受数据
28           window[options.callbackName] = (res) => {
29               //在接受到了参数动态删除这个script节点和window上面的方法
30               delete window[options.callbackName];
31               document.body.removeChild(scriptDom)
32               //接受成功后调用resolve
33               if (res) {
34                   resolve(res)
35               } else {
36                   reject("服务器暂没有获取到数据")
37               }
38           }
39           //动态创建script标记,错误的监听
40           scriptDom.addEventListener('error', () => {
41               delete window['jsonpCallback'];
42               document.body.removeChild(script);
43               reject('服务器加载失败!');
44           });
45           document.body.append(scriptDom)
46       })
47   }

调用方式

 1 <script>
 2         // jsonp("http://localhost:7001/api", {
 3         //     user: "zhangsan",
 4         //     age: "18"
 5         // }).then(res=>{
 6         //     console.log(res);
 7         // }).catch(err=>{
 8         //     console.log((err,"失败"))
 9         // })
10 
11 
12         jsonp(" http://localhost:3000/api", {
13             user: "zhangsan",
14             age: "18"
15         }).then(res => {
16             console.log(res);
17         }).catch(err => {
18             console.log((err, "失败"))
19         })
20     </script>

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

express的代码展示

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

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

原文地址:https://www.cnblogs.com/cq1715584439/p/11353383.html