首页>>前端>>JavaScript->给axios添加jsonp请求

给axios添加jsonp请求

时间:2023-11-29 本站 点击:1

从跨域报错讲起

假如我有一个测试服务器,地址是 10.128.119.119,端口是默认的 80 端口,那么一个简单的接口的地址可以是这样的:http://10.128.119.119/api/get/username

那么这个接口可不可以被自由访问呢?

答案是可以的。你用 postman 在任何网络下都可以访问这个接口。

但是如果你通过浏览器在本地访问,比如在页面http://localhost:8000/usercenter.html 中调用这个接口

$.get('http://10.128.119.119/api/get/username',function(res){console.log(res)})

打开一看,报错了

No 'Access-Control-Allow-Origin' header is present on the requested resource.'

这是因为浏览器有一个安全策略,叫做同源策略。

什么是同源策略?

所谓同源,是指两个地址的"协议","域名","端口"这三者都相同。

只有当两个地址同源时,浏览器才允许它们之间进行数据通信,这就是同源策略。

同源策略(Same origin policy),最开始是由网景公司(Netscape)提出的安全策略并引入浏览器中,现在已经成为浏览器最基础的安全策略。它确保了应用的资源只能被应用自身访问。从而帮用户避免了大量来自第三方的恶意攻击,比如 XSS(跨站脚本攻击)、CSRF(跨站请求伪造) 等。

所以,当你看到上面的No 'Access-Control-Allow-Origin' header is present on the requested resource.报错信息,其实是浏览器拦截了从后端返回的数据,不让当前的页面访问这些数据,从而一方面避免对本地数据造成污染,一方面也避免用户数据比如 cookie 信息、账号、密码等个人信息的泄漏风险。

开发环境下的同源策略

当然了,同源策略是好的,但偶尔也会对我们造成阻碍。

比如在软件的开发环境下,我们本地的服务一般是http://localhost,这肯定和接口地址是不同源的呀,这时候同源策略貌似成了我们的阻碍。

针对这种情况,网上有非常多的解决办法,很多社区也有自己成熟的方案

比如,我们可以通过 nodeJS 搭建一个微服务参见,再利用 http-proxy-middleware 对 ajax 请求进行转发来实现跨域,或者利用 webpack 跨域代理配置参见也可以解决。

不过,本文今天想说的不是上面的,而是很早以前就出现的 jsonp。

jsonp 的前世今生

在 vue、react 出现之前,jsonp 可以说是大名鼎鼎了。jquery 中的 ajax 默认就添加了 jsonp 请求

$.ajax({url:"http://10.128.119.119/api/get/username",type:"GET",dataType:"jsonp",jsonpCallback:"callback"});functioncallback(res){}

你可能在之前就发现了,对于接口,不同源就报错,但是对于 img、js 这种文件资源,当你使用<img src="xxx" />或者<script src="xxx"></script>的时候,似乎同源策略并没有发生作用。

是的,html 元素的 src 属性是一个例外,src 属性不受到同源策略的限制,也正是基于此,才有了 jsonp,也因此,jsonp 只能支持 get 请求。

一个最最简单的 jsonp 请求如下:

http://digi.duodiangame.com/digMineral/interfaces/task/reportDailySignin.do?callback=cb_callback&user_id=AAA

当你把这个 url 放入浏览器地址栏里打开,你会看到这个 url 返回了一个函数的调用:cb_callback({"Error":"用户数据错误"});

如果当前页面恰好有个叫做 'cb_callback' 的函数,那么这个函数就会执行,参数就是后台真正的返回值。

varcb_callback=function(data){alert(data.Error)}document.write('<scriptsrc="http://digi.duodiangame.com/digMineral/interfaces/task/reportDailySignin.do?callback=cb_callback&user_id=AAA"></script>')

大家可以把这段代码复制到控制台看一下效果

以上就是 jsonp 能够获取数据的原理了。

封装 jsonp

我们封装一个简单的 jsonp 来解释 jsonp 应该如何来实现

functionjsonp(url,data,fn){if(!url)thrownewError('urlisnecessary')constcallback='CALLBACK'+Math.random().toString().substr(9,18)constJSONP=document.createElement('script')JSONP.setAttribute('type','text/javascript')constheadEle=document.getElementsByTagName('head')[0]letret='';if(data){if(typeofdata==='string')ret='&'+data;elseif(typeofdata==='object'){for(letkeyindata)ret+='&'+key+'='+encodeURIComponent(data[key]);}ret+='&_time='+Date.now();}JSONP.src=`${url}?callback=${callback}${ret}`;window[callback]=function(r){fn&&fn(r)headEle.removeChild(JSONP)deletewindow[callback]}headEle.appendChild(JSONP)}

封装完成以后,简单的写个后台接口,这里要注意,因为 jsonp 要求后台返回的是一个函数的调用,就是类似func(response),所以我们要动态的获取函数名,然后返回函数名的调用

<?php$data=".......";$callback=$_GET@['callback'];echo$callback.'('.json_encode($data).')';exit;?>

一个简单的封装就完成了。

axios中如何使用jsonp

当 jsonp 和 axios 碰撞的时候,会发出什么样的火花呢?

因为 axios 不支持 jsonp,所以我们需要在 axios 上添加 jsonp 方法,另外我们可以通过 promise 来替代回调参数

axios.jsonp=(url,data)=>{if(!url)thrownewError('urlisnecessary')constcallback='CALLBACK'+Math.random().toString().substr(9,18)constJSONP=document.createElement('script')JSONP.setAttribute('type','text/javascript')constheadEle=document.getElementsByTagName('head')[0]letret='';if(data){if(typeofdata==='string')ret='&'+data;elseif(typeofdata==='object'){for(letkeyindata)ret+='&'+key+'='+encodeURIComponent(data[key]);}ret+='&_time='+Date.now();}JSONP.src=`${url}?callback=${callback}${ret}`;returnnewPromise((resolve,reject)=>{window[callback]=r=>{resolve(r)headEle.removeChild(JSONP)deletewindow[callback]}headEle.appendChild(JSONP)})}

调用方式也发生了变化:

axios.jsonp(url,params).then(res=>console.log(res)).catch(err=>console.log(err))

到了这里文本的内容就到此结束了,文中有任何错误,请在评论区留言哦~

作者:晴天同学


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/JavaScript/685.html