大概算是学习记录吧。
目录
1.1.1 ajax(asynchronous JavaScript and XML)
1. 前言
1.1 axios出现的原因
很久以前,当浏览器页面向服务器请求数据时,整个页面都会进行刷新,这会造成网络资源的占用,为了提高数据请求效率,异步网络请求ajax出现,它可以在页面无刷新的情况下请求数据。jQuery封装的ajax。原生的XHR(XMLHttpRequest),以及axios都可以实现异步网络请求。
1.1.1 ajax(asynchronous JavaScript and XML)
传统的ajax请求是基于XHR对象的,可以直接使用,但是其配置和调用方式十分混乱,所以在真实开发中很少使用,因此在MVC(Model模型-View视图-Controller控制器)框架中,取而代之使用jQuery-ajax实现前后端数据交互。而现在使用更多的则是fetch请求。
1.1.2 jQuery-ajax
jQuery-ajax底层原理也是对传统的ajax,XHR对象进行封装,但是在前端框架MVVC时代,如果在继续用ajax就还需要单独引入jquery,代码量巨大,得不偿失。因此针对于框架的网络请求就出现了。
1.1.3 axios
尤雨溪本人亲自推荐。相较XHR——简单易用,相较jQuery——尺寸小且提供了易于扩展的接口,是专注于网络请求的库。
1.2 axios是什么?
axios是一个基于promise的http库,可以用在浏览器和node.js中。
特点:
①支持从浏览器中创建XHR
②支持从node.js创建http请求
③可以调用promise的api
④能拦截请求和响应
⑤能转换请求数据和响应数据
1.3 axios二次封装的目的及应用场景
目的:对api进行统一管理,易于项目的维护和迭代,接口再多也不怕不怕啦。
(当没有二次封装时,若后端改了接口参数,就必须找到使用该接口的页面进行修改,非常繁琐)
业务场景:
①全局请求配置
②get/post/put/delete等请求的promise封装
③全局请求状态管理,供加载动画等使用
④请求携带token,权限错误统一管理
⑤路由跳转取消当前页面请求
⑥二次封装请求拦截器和响应拦截器
⑦多环境:开发、测试、生产
⑧统一错误处理:401、404、500等
2. 二次封装全过程
2.1 安装axios
npm i axios
2.2 添加文件结构
下图结构参考开源项目vben-admin。
在项目src文件夹下的util文件夹中添加一个http文件夹(也可以不放在util文件夹中),存放关于axios请求的相关文件,然后在http的axios文件夹中新建index.js文件(直接放在http文件夹下也可),用于封装axios。最后在src文件夹下新建api文件夹用于集中管理接口。
2.3 封装axios,进行初始配置
在index.js文件中使用axios的create方法创建axios实例,并传入配置,同时设置请求拦截器和响应拦截器。(注:也有很多人的思路是封装一个函数,在函数内创建实例,然后在需要发送请求的位置调用这个函数,意味着每发送一个请求,都会创建一个新的axios实例,vben-admin就是这样做的)
如果后端服务有统一的网关入,那么在此仅创建一个实例就可以,但是如果后端接口地址有多个(www.test1.com、www.test2.com),并且一些默认配置还不同,如超时时长不同(1000ms、2000ms),此时就可以创建多个实例,用不同的实例去请求不同的接口,配置相关信息。
以下代码只创建了一个实例:
其中,axios的常见配置选项如下:
url:请求地址(必写)
method:请求方法,默认为get
baseURL:baseURL会添加到url前(url是绝对地址除外)
headers:自定义请求头信息
params:查询参数。只有get请求的params位于url后,其他请求的params都在请求体中。
data:请求体中的数据。此选项只适用于以下请求方式:put/post/patch。
timeout:请求超时时间。
withCredentials:设置是否允许携带cookie等凭证信息。
transformRequest:请求数据的转换函数。此选项只适用于以下几种请求方式——put/post/patch。
transformResponse:响应数据的转换函数。
validateStatus:判断请求状态是否成功的函数,可以自定义规则。
onUploadProgress:上传进度事件
onDownloadProgress:下载进度事件
maxContentLength:响应数据的最大长度
maxRedirects:重定向的最大次数
cancelToken:请求取消的令牌
2.3.1 请求拦截器
作用:在发送请求前进行一些操作。
原理:axios是对ajax的封装,它暴露出来的拦截器其实是写了一个方法,将ajax放在这个方法里卖弄,在执行的时候,先将请求时要添加给请求头的数据(如token等)都赋值给一个变量,然后统一传给ajax,然后才执行ajax。也就是说,请求拦截器就是将添加数据的过程抽离出来,并在发送ajax请求前执行。
使用场景:给所有的axios请求设置请求头(否则需要手动给每一个axios设置)、统一添加cookie/token、请求体加验证....
2.3.2 响应拦截器
作用:在接受到响应后执行一些操作。
原理:当请求结果返回后,先不直接导出,而是先对响应码等信息进行操作,处理好之后再到处给页面。也就是将处理对象响应码的过程抽离出来,构成所谓的响应拦截器。
使用场景:响应数据的统一处理,常用来对请求错误进行统一处理。
2.4 封装各类请求
有了axios实例和响应的配置,接下来就在常用的GET、POST等请求上应用上面的配置,封装请求方法的目的是为了使用起来更方便。
这里是否要对GET、POST等请求再封装一层promise?我看网上大家的意见都不太统一,但更多人觉得多封装一层是多余的,因为axios返回的就是promise对象。
如果再套一层promise的话,return的时候直接new Promise,代码如下:
如果不套promise,代码如下:
我在编写这部分代码的时候好几次掉进了坑,得到的请求结果怎么都是undefined,仔细检查发现,主要需要注意的地方有两个:①直接返回axios请求时,如果使用了then和catch,那么需要在then或catch中返回处理后的结果,如上面我在then中将响应结果中的data属性进行了返回,如果没有return结果的话,那这个封装好的post函数在调用时,得到的结果就是undefined;②如果不是直接返回axios请求,而是在这个函数中使用axios发请求,然后返回结果,那么需要将这个函数修改为异步函数,否则返回的结果也会是undefined。
注:then到底需不需要用?我的理解:如果需要对响应数据进行处理的话,那么可以在then的回调函数中进行(但是对响应数据的处理在响应拦截器中也可以完成,两者的区别和执行顺序我现在还没弄清楚)。
补充:axios常用语法如下:
axios(config): 通用/最本质的发任意类型请求的方式
axios(url[, config]): 可以只指定 url 发 get 请求
axios.request(config): 等同于 axios(config)
axios.get(url[, config]): 发 get 请求
axios.delete(url[, config]): 发 delete 请求
axios.post(url[, data, config]): 发 post 请求
axios.put(url[, data, config]): 发 put 请求
axios.defaults.xxx: 请求的默认全局配置
axios.interceptors.request.use(): 添加请求拦截器
axios.interceptors.response.use(): 添加响应拦截器
axios.create([config]): 创建一个新的 axios(它没有下面的功能)
axios.Cancel(): 用于创建取消请求的错误对象
axios.CancelToken(): 用于创建取消请求的 token 对象
axios.isCancel(): 是否是一个取消请求的错误
axios.all(promises): 用于批量执行多个异步请求
axios.spread(): 用来指定接收所有成功数据的回调函数的方法
补充:axios配置的优先级(由低到高):全局配置 < 实例配置 < 请求时配置
// 全局配置
axios.default.timeout = 3000
// 实例配置
let instance = axios.create()
instance.default.timeout = 2000
// axios请求时配置
instance.get('/url', {timeout:1000})
2.5 API统一管理
进入我们最初创建的api文件夹,新建user.js文件,在这里定义和用户相关的api,我们需要将刚刚封装好的请求列表导入然后使用,如以下是一个简单的用户登录api:
不同类型与功能的api放在不同的文件夹中,这样方便管理和后续查找维护。
2.6 在组件中使用api
以下是一个最简单的登录跳转(很多处理在这里还没完成,仅展示如何使用),就两步,导入+使用,我在这里是将用户对应的操作放到了store中,所以稍微绕一下:
3. 心得
至此,axios的基础二次封装就结束了,更多复杂的功能就可以在这个基础上进行添加,如拦截器的设置、更多不同的请求方法的封装.......在整个梳理过程中我最大的感受是,涉及到很多基础的知识,如async/await与promise、js的事件循环机制、axios请求的各种配置等等,细节的地方稍不注意就会导致结果和预期不同,所以还是得反复练习把基础打牢。
后续想到什么再进行补充。