网络请求axios
一、网络请求模块的选择
1、常见的网络请求模块,以及优缺点对比。
Vue中发送网络请求有非常多的方式, 那么, 在开发中, 如何选择呢?
选择一: 传统的Ajax是基于XMLHttpRequest(XHR)
缺点:
- 配置和调用方式等非常混乱。
- 编码起来看起来就非常麻烦。
- 所以真实开发中很少直接使用, 而是使用jQuery-Ajax。
选择二: 在前面的学习中, 我们经常会使用jQuery-Ajax,相对于传统的Ajax是非常好用的。
既然这么好用为什么也不选择它呢:
- 首先, 我们先明确一点: 在Vue的整个开发中都是不需要使用jQuery了。
- 那么, 就意味着为了方便我们进行一个网络请求, 特意引用一个jQuery, 是多此一举的。完全没有必要为了用网络请求就引用这个重量级的框架。
选择三: 官方在Vue1.x的时候, 推出了Vue-resource。Vue-resource的体积相对于jQuery小很多,另外Vue-resource是官方推出的。
为什么不选择它呢?
- 在Vue2.0退出后, Vue作者就在GitHub的Issues中说明了去掉vue-resource, 并且以后也不会再更新.
- 那么意味着以后vue-reource不再支持新的版本时, 也不会再继续更新和维护。
- 对以后的项目开发和维护都存在很大的隐患。
选择四: 在说明不再继续更新和维护vue-resource的同时, 作者还推荐了一个框架: axios。axios有非常多的优点, 并且用起来也非常方便。
2、JSONP的原理和封装
在前端开发中, 我们一种常见的网络请求方式就是JSONP,使用JSONP最主要的原因往往是为了解决跨域访问的问题。
JSONP的原理是什么呢?
- JSONP的核心在于通过
JSONP如何封装呢?
来试着封装一个处理JSONP的代码:
3、为什么选择axios?
功能特点:
- 在浏览器中发送 XMLHttpRequests 请求
- 在 node.js 中发送 http请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据等等
4、axiox请求方式
支持多种请求方式:
axios(config)
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
二、axios框架的基本使用
首先要使用axios,应该先通过 npm install axios --save 安装。
通过一个代码简单尝试一下:
默认情况下,axios是通过get请求的。httpbin.org这个网站可以用来做网页请求的测试。
url后面还可以直接通过?添加参数,也可以url就是地址,通过params这个对象来定义参数,axios框架内部会自动将params添加到url后面(params为专门针对get请求的参数拼接)
三、axios发送并发请求
有时候, 我们可能需要同时发送两个并发请求,并且两个请求都到达的时候在执行相应的功能,axios提供了相应的API。使用axios.all, 可以放入多个请求的数组。axios.all([]) 返回的结果是一个数组,使用 axios.spread 可将数组 [res1,res2] 展开为 res1, res2。
四、axios的配置信息
在大多数页面请求中,url前面的部分都是固定的,比如说:127.0.0.1:8080,这部分是固定的,可以把它拉到一个BaseURL里面去,url里面就不用写这么长的路径。但是把这部分固定的路径提取出来后,每个axios里面都需要加上这个BaseURL,也是非常麻烦的。
事实上, 在开发中可能很多参数都是固定的。这个时候可以对这些固定的参数进行一些抽取, 也可以利用axiox的全局配置。采用axios的全局配置就不用在每个axios里面都加上BaseURL了。例如如下代码,就是axios的全局配置:
axios.defaults.baseURL = ‘127.0.0.1:8888’;
axios.defaults.headers.post[‘Content-Type’] = ‘application/x-www-form-urlencoded’;
常见的配置选项:
请求地址:url: ‘/user’,
请求类型:method: ‘get’,
请求根路径:baseURL: ‘http://www.mt.com/api’,
请求前的数据处理:transformRequest:[function(data){}],
请求后的数据处理:transformResponse: [function(data){}],
自定义的请求头:headers:{‘x-Requested-With’:‘XMLHttpRequest’},
URL查询对象:params:{ id: 12 }, **注意:**这种模式是在get的情况下使用的
查询对象序列化函数:paramsSerializer: function(params){ }
request body:data: { key: ‘aa’}, **注意:**这种模式是在post的情况下使用的
超时设置:timeout: 1000,
跨域是否带Token:withCredentials: false,
自定义请求处理:adapter: function(resolve, reject, config){},
身份验证信息:auth: { uname: ‘’, pwd: ‘12’},
响应的数据格式 json / blob /document /arraybuffer / text / stream:responseType: ‘json’,
这些配置信息在用到的时候去查即可。
五、axios的实例和模块封装
1、axios实例
为什么要创建axios的实例呢?
当我们从axios模块中导入对象时, 使用的实例是默认的实例。当给该实例设置一些默认配置时, 这些配置就被固定下来了。但是后续开发中, 某些配置可能会发生变化。比如某些请求需要使用特定的baseURL或者timeout或者content-Type等。这个时候, 我们就可以创建新的实例, 并且传入属于该实例的配置信息。
像上面这种,使用的是全局的axios,是一个默认的实例。但在大型的项目中,有可能有些请求需要到不同的服务器上面获取,那么baseURL就不是你前面加到默认axios里面的baseURL了,那么你直接写个url的话,请求的时候就会拼上错误的baseURL了,怎么做了呢?就是自己定义一个新的axios实例,例如下面的代码:
总结:如果有某些请求不在同一个服务器里面或者使用的某些配置不一样的话,那么就通过创建一个axios实例,定义新的配置来满足不同情况下的需求。
2、axios的封装
向上面的代码,所有的网页请求都是写在同一个main.js里面的。或者说,你在项目开发的过程中,某些网络请求需要在组件创建完毕之后(也就是在生命周期create里面回调axios)进行的,并且将请求的数据放到data里面,然后进行页面展示。这样的话,每个需要网络请求的组件里面都需要在create里面回调axios进行网络请求,这种方式对网络请求的框架依赖性非常高,假如有一天该框架不在维护的时候,那么项目在进行替换网络请求框架的时候,就要在每个页面里面更换,所以该项目在后期更新维护的时候就非常麻烦。比如如下代码:
为了解决这种情况,我们可以使用网络请求的代码封装成一个文件,其他页面面向这个文件进行网络请求,我们只要在这个文件里面使用axios框架即可。那么,如果有一天,axios不在更新维护了,项目需要更换网络请求框架的时候,我们只需修改该文件即可,其他文件无需做修改。
所以在真实的开发中,需要将网络请求封装起来。以下有三种方式:
其中,方法三是推荐使用的。因为axios实例返回的就是promise,就不用在通过resolve回调然后在执行then了。
六、axios的拦截器的使用
1、如何使用拦截器?
axios提供了拦截器,用于我们在发送每次请求或者得到相应结果后,进行对应的处理。即提供了请求成功的拦截,请求失败的拦截,也提供了相应成功和失败的拦截。(四种拦截)
如何使用拦截器呢?
2、拦截器中都做什么呢?
请求拦截可以做到的事情:
1.config中的信息不符合服务器的要求
2.每次发送网络请求,都希望在界面显示网络请求的图标
3.某些网络请求,比如说登录,必须携带一些信息(token),假如没有登录跳转到登录界面登录
4.对请求的参数进行序列化
将数据中的对象转换为参数形式---------qs.parse(config.data)
将数据中的参数转换为对象形式---------qs.stringify(config.data)
注意:要先导入import * as qs from “autoprefixer”;
5.请求拦截中错误拦截较少,通常都是配置相关的拦截。可能的错误比如请求超时,可以将页面跳转到一个错误页面中。
响应拦截中完成的事情:
1.响应的成功拦截中,主要是对数据进行过滤。
2.响应的失败拦截中,可以根据status判断报错的错误码,跳转到不同的错误提示页面。
具体应用场景的代码:
请求拦截:
// http request 拦截器
instance.interceptors.request.use(
config => {
const token = sessionStorage.getItem('token')
if (token ) { // 判断是否存在token,如果存在的话,则每个http header都加上token
config.headers.authorization = token //请求头加上token
}
return config
},
err => {
return Promise.reject(err)
})
响应拦截:
instance.interceptors.response.use(
response => {
// 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据
// 否则的话抛出错误
if (response.status === 200) {
return response.data;
} else {
return response;
}
},
// 服务器状态码不是2开头的的情况
// 这里可以跟你们的后台开发人员协商好统一的错误状态码
// 然后根据返回的状态码进行一些操作,例如登录过期提示,错误提示等等
// 下面列举几个常见的操作,其他需求可自行扩展
error => {
if (error.response.status) {
switch (error.response.status) {
// 401: 未登录
// 未登录则跳转登录页面,并携带当前页面的路径
// 在登录成功后返回当前页面,这一步需要在登录页操作。
case 401:
vant.Toast.fail("身份验证失败,请关闭重新进入。");
break;
// 403 token过期
// 登录过期对用户进行提示
// 清除本地token和清空vuex中token对象
// 跳转登录页面
case 403:
vant.Toast.fail("登录过期,请关闭重新进入。");
// 清除token
break;
// 404请求不存在
case 404:
vant.Toast.fail("您访问的网页不存在。");
break;
// 其他错误,直接抛出错误提示
default:
vant.Toast.fail(error.response.data.message);
}
return error.response;
}
}
);