前端框架Vue自学之axios(九)
我的最新博客在:Secret_wu's coding note
终极目标:掌握和使用Vue(全家桶:Core+Vue-router+Vuex)
本博客目的:记录Vue学习的进度和心得(axios)
内容:学习和使用axios,网络模块封装。
正文:
axios
一、网络模块封装
1、网络请求
Vue中发送网络请求有非常多的方式,那么,在开发中,如何选择?
选择一:传统的Ajax是基于XMLHttpRequest(XHR)。一般不用,因为配置和调用方式等非常混乱。所以真实开发中很少直接使用,而是使用jQuery-Ajax。
选择二:jQuery-Ajax。相对于传统的Ajax,其有优势。但是也不选择它,因为Vue的整个开发中都是不需要使用jQuery。完全没有必要为了用网络请求就引用这个重量级的框架。
选择三:官网vue1.x的时候,推出了Vue-resource插件。Vue-resource的体积相对于jQuery小很多,并且是官网的。但也不选,Vue2.0推出后,作者不在更新。使用这个对以后的项目开发和维护存在很大的隐患。
选择四:axios。vue作者说明不在继续更新和维护Vue-resource插件,但推荐了一个框架:axios。它有很多优点,并且用起来很方便。
2、jsonp
在前端开发中,我们一种常见的网络请求方式就是JSONP。使用JSONP最主要的原因往往就是为了解决跨域访问的问题。
JSONP的原理是:
但我们这里还是重点研究axios!
二、axios
1、axios的功能特点
axios:ajax i/o system(一个老师理解的翻译,网上也没找到具体指的是什么)。
在浏览器中发送XMLHttpRequests请求;在node.js中发送HTTP请求;支持Promise API;拦截请求和响应;转换请求和响应数据等等。
2、axios支持多种请求方式
axios支持多种请求方式,和http请求有关,例如request,post,get,put等。
3、在vue下的axios的简单使用
首先创建vue项目,这里为了更好看到目录结构,我们使用Vue CLI2安装,终端输入vue init webpack learnaxios,然后选择默认和不安装vue-router等插件(具体步骤可以看我之前关于Vue CLI的博客)。(接着把一些我们不用的代码删掉,如HelloWorld.vue相关的东西)
现在假设我们在App.vue里面发送一个网络请求,从服务器请求过来一个数据,然后对数据进行展示。
首先,安装axios。npm install axios --save(运行是依赖)
然后,导入使用。在任意文件都可以使用axios。为了演示,我们在main.js中使用axios,以axios(config)的方式。axios是支持Promise的。url只是
这个url是对应服务器端口路径的数据,即后端接口:http://123.207.32.32:8000/home/multidata
之后运行代码,在控制台就打印这个网络请求的数据(从服务器端来的数据)。其是一个对象,里面包含数据,配置,请求方式,状态等信息。但注意,这些信息(除了data数据)都是axios框架加上的,不是在服务器端写返回的。
axios参数中,只使用url的默认请求方式是get请求。我们可以使用method,来设置请求方式,如post。当然也可以使用axios.post()的形式。
(这个服务器接口是不支持post方式请求的,只是演示而已)
此外,httpbin.org可以对网站进行很多的模拟,用于测试等。
如果我们想使用query的网络请求,除了可以直接以get方式请求完整接口,也可以使用params。
三、axios发送并发请求
我们想做发送两个并发的请求,并且要等两个请求都到达后,才能做相应处理的需求。之前我们是使用Promise.all来解决的。这里我们使用axios框架。
使用axios.all()对多个网络请求进行合并,参数是传入数组,里面放置请求,如请求1和请求2。然后在最后用.then()函数拿到最终结果。
(基本格式示意)
例如我们把第二章的两个请求当做并发请求。
最后结构是一样的。结果是一个数组。
如果我们想把数组展开,使用axios.spread可以将数组[res1,res2]展开为res1, res2。
四、axios的配置信息相关
1、全局配置
在上面一些例子中,我们的BaseURL是固定的。事实上,在开发中可能很多参数都是固定的(例如一些headers请求)。
这个时候我们可以进行一些抽取,也可以利用axios的全局配置。
利用axios.defaults可以对一些属性进行全局配置,例如baseURL。
2、常见的配置选项
五、axios的实例和模块封装
1、axios的实例
为什么要创建axios的实例?
当我们从axios模块中导入对象时,使用的实例是默认的实例。当给该实例设置一些默认配置时,这些配置就被固定下来了。但后续开发中,某些配置可能会不太一样,比如某些请求需要使用特定的baseURL或者timeout或者content-Type等。这个时候(使用上述的参数的全局配置就不合适),我们就可以创建新的实例,并且传入属于该实例的配置信息。
当项目越来越大的时候,服务器接口不一定是一个端,它可能是把服务器发到多个端。通过nginx部署服务器,做反向代理。服务器分布式,当服务器在部署的时候,当并发量很大的时候,一个服务器是无法满足业务需求,所以一般需要多个服务器(每个服务器一个ip地址),但是客户端需要知道哪里请求对应哪里服务器(ip地址),就很麻烦。所以nginx相当于部署一个代理服务器,当客户端发送请求时,指向都是这个代理服务器,先经过代理服务器,然后代理服务器通过判断哪个服务器是比较空闲合适的,在把请求发到对应服务器。
2、创建对应的axios的实例
axios.create(config)创建这个config的实例。
还可以正常拿到结果。
当我们还有别的请求,可以类似地创建instance2等,设置单独的baseURL,timeout等。
3、模块封装
之前我们写的axios代码都是在main.js中写的(为了演示),真实开发中,我们需要网络请求模块封装。
方式一:我们可以在需要使用到axios的组件中导入axios,然后用create()周期钩子使用axios,并输出结果,把结果用data保存,并展示到对应地方。
但这种方式导致,我们要用到axios的组件都必须导入axios,然后进行配置和使用,这样组件对第三方框架依赖太强了。这样维护会麻烦。
补充:真实开发中,只要引入第三方的东西,千万不要在每个组件都对这个第三方东西依赖,一旦第三方的东西不能用了(如不更新和维护了),那么意味着对应每个组件都需修改。所以我们必须对第三方的东西进行封装,让其面向我们的组件。这样维护只需修改封装的文件即可。
方式二:所以我们对axios进行封装。
首先,在src下创建network文件夹。network文件夹下创建request.js。如果我们是要导入多个实例的话,写成export function XX的形式(而不是export default形式)。注意上一节说过不要创建全局配置,而是使用axios配置。
然后发送出真正的网络请求。通过传入success函数和failure函数导出网络请求结果。
然后在main.js中,导入request模块,使用request,把config配置和sucees,failure函数对应写好。
最后结果还是可以网络请求得到。
但这不是我们的最终方案。
方式三:我们的最终方案是用Promise。(但方式四才是最终版本)
request.js使用Promise。
main.js使用的request时使用then(),catch()
一样可以请求出正常的结果。
方式四:简化方式三。
因为由axios.create()创建的axios实例本身就是一个Promise(源码体现出的)。所以直接返回实例即可。
使用request和方式三一致。显示的请求结果也是正常的。
优点:由于我们把axios封装到一个文件内,并且使用Promise导出网络请求的结果。所以如果某一天axios不在更新和维护,我们可以直接修改这个文件,也写成使用Promise导出网络请求的方式,其他使用这个网络请求的组件文件也不需要修改了。(这才是封装啊)
六、axios拦截器的使用
1、axios拦截器
axios提供了拦截器,用于我们在发送每次请求或者得到响应后,进行对应的处理。如url拼接等。axios提供了4种拦截器:请求成功的拦截和请求失败的拦截,响应成功的拦截和响应失败的拦截。(客户端请求,服务端响应)
具体怎么使用呢?(注意,拦截也要返回结果,后面会说)
全局拦截:axios.interceptors 。但通常我们使用的是实例拦截。
实例拦截:(instance.interceptors.request.use请求拦截,instance.interceptors.response.use响应拦截)
请求拦截,instance.interceptors.request.use里面有两个参数(看源码),一个是拦截成功的函数,一个是拦截失败的函数。
(源码)
此时,拦截了请求,在控制台打印了结果,但是报了一个错误。是由于请求被拦截了,如果没有使用reture把请求结果返回,则出错误信息。
所以,使用拦截器的时候记得加上reture把结果返回。
此时就没有报错了。
2、请求情况分析
现在,我们是拦截了请求,我可以做一些操作。通常情况有:
情况一:config中的一些信息不符合服务器要求,需要某些操作。例如修改特殊的header。
情况二:每次发生网络请求时,都希望在界面中显示一个请求的图标。例如一个转圈表示等待的图标。相当于正在请求时,显示图标,请求结束后,图标消失,显示页面的效果。
情况三:某些网络请求(比如登录(token)),必须携带一些特殊的信息。首先拿到一个url,看是否是些特殊请求,在这请求中有没有传入token信息,可以判断用户有没有登录,如有token,则可以让其继续发送请求;如果没有,给一些错误提示,让其登录,再进行访问。
3、响应拦截
instance.interceptors.response.use 响应拦截,也有有两个参数。第一个是结果。由于服务器响应过了,这里拿到的是结构。第二个是失败的情况。
结果显示。
当我们(人为)让请求失败,例如给个错误的url。则正常输出错误结果。
一样地,当我们拦截后,必须返回结果,不然请求的东西是会报错的。
通常返回的是data。(其他信息是axios框架后面添加的,有时候我们只需要data)