前端学习笔记(16)-Axios封装
axios流程及封装,config.headers的对象可能未定义问题解决
1.Axios介绍
1.1 概述
Vue前端开发少不了向服务器请求数据,我们选择axios插件,他是一款功能强大,且易用的网络请求工具。
1.2 全称
ajax i/o system
1.3 功能介绍
1.3.1 axios功能特点
在浏览器中发送 XMLHttpRequests 请求
在 node.js 中发送 http请求
支持 Promise API
拦截请求和响应
转换请求和响应数据
1.3.2 支持多种请求方式
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]])
2.axios网络请求最基本流程
2.1导入(安装就省略了)
import axios from 'axios'
2.2 简单的实例
axios({
// 配置代码
url:'xxx', // 设置请求的地址
method:"GET", // 设置请求方法
params:{ // get请求使用params进行参数凭借,如果是post请求用data
type: '',
page: 1
}
}).then(res => {
// res为后端返回的数据
console.log(res);
})
method中是axios的请求类型方法, 而url为请求的URL地址,在then方法中获取服务器返回的数据并处理。
2.2.5 axios全局可配置项列表
这些是创建请求时可以用的配置选项。只有 url 是必需的。
配置项及示例 | 说明 |
url: '/user', | 请求地址 |
method: 'get', | 响应头信息 |
baseURL: ‘http://www.xxx.com/api’, | 请根路径 |
transformRequest:[function(data){}], | 请求前的数据处理 |
transformResponse: [function(data){}], | 请求后的数据处理 |
headers:{'x-Requested-With':'XMLHttpRequest'}, | 自定义的请求头 |
params:{ id: 12 }, | URL查询对象 |
paramsSerializer: function(params){ } | 查询对象序列化函数 |
data: { key: 'aa'}, | request body |
timeout: 1000, | 超时设置(s) |
withCredentials: false | 跨域是否带Token |
adapter: function(resolve, reject, config){}, | 自定义请求处理 |
auth: { uname: '', pwd: '12'}, | 身份验证信息 |
responseType: 'json', | 响应的数据格式 json / blob /document /arraybuffer / text / stream |
2.3 对响应结果进行处理
.then((data) => {
// todo: 真正业务逻辑代码
console.log(data);
}, (err) => {
// 错误处理代码
if (err.response.status === 401) {
// handle authorization error
}
if (err.response.status === 403) {
// handle server forbidden error
}
// 其他错误处理.....
console.log(err);
});
在.then中可以写一些业务逻辑代码,或是对传回来响应结果的错误信息进行处理。
2.3.5 axios响应结果列表
响应结果 | 说明 |
data | 实际响应回来的数据 |
header | 响应头信息 |
status | 响应状态码 |
statusText | 响应状态信息 |
以上就是一个比较简单的axios请求流程,但是当随着项目规模增大,如果每发起一次HTTP请求,就要把这些比如设置超时时间、设置请求头、根据项目环境判断使用哪个请求地址、错误处理等等操作,都需要写一遍,这种重复劳动浪费时间,还会造成代码的冗余以及难以维护的问题,为了提高我们的代码质量,我们应该在项目中二次封装axios 再使用。
3.axios封装
3.1 axios拦截器
在正常项目中,我们需要对发起的请求进行拦截,或是在响应被 then 或 catch 处理前拦截以实现一些业务功能。比如一些网站过了一定的时间不进行操作,就会退出登录让你重新登陆页面,或是取消重复请求,axios自带的拦截器可以很好的完成这些功能。
其一般分为两种:请求拦截器、响应拦截器。
请求拦截器:在请求发送前进行必要操作处理,例如添加统一cookie、请求体加验证、设置请求头、处理请求token的统一注入问题等,相当于是对每个接口里相同操作的一个封装;
在请求拦截器中拦截了请求后,我们需要将请求继续转发出去,让请求访问服务器。这样请求才能成功,返回服务器数据。
config是拦截器拦截到所请求的配置信息,继承了AxiosRequestConfig接口,无论什么时候都需要return config,否则报错。
const instance = axios.create({})
// 请求拦截
instance.interceptors.request.use(
(config) => {
// 在发送请求之前做些什么
return config;
},
(error: any) => {
// 对请求错误做些什么
return Promise.reject(error)
}
)
响应拦截器:同理,响应拦截器也是如此功能,只是在请求得到响应之后,对响应体的一些处理,通常是数据统一处理等,也常来判断登录失效等。
instance.interceptors.response.use(
(res: any) => {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
let msg = res.data['msg'] || '未知错误,请联系管理员'
switch (code) {
case 401:
msg = '认证失败,无法访问系统资源'
break
//......
case 'default':
msg = '系统未知错误'
break
}
if (code === 200) {
return Promise.resolve(res)
} else {
//ElMessage.error(msg)
return Promise.reject(res)
}
},
(error: any) => {
// 超出 2xx 范围的状态码都会触发该函数
// 对响应错误做点什么
return Promise.reject(error)
}
)
3.2 如何封装
对于冗余重复的代码,很容易想到创建一个网络请求类的.ts文件,和后端协商好一些约定,请求头,状态码,请求超时时间等;并创建axios实例,设置请求头与超时时间。编写请求方法,也就是根据常用的get、post进行一个再次封装,使用时直接调用。对于项目所需要的添加统一cookie、请求体加验证、设置请求头的功能,以及错误处理,利用3.1所介绍的拦截器实现。
3.2.1 设置请求头与超时时间、接口请求前缀
根据开发、测试、生产环境的不同,接口请求前缀需要加以区分,在全局设置更为合适。大部分情况下,请求头等大部分配置也都是固定的,先将请求头作为基础配置。当需要一些特殊的请求头时,将特殊请求头作为参数传入,覆盖基础配置。
const instance = axios.create({
baseURL: process.env.VUE_APP_INTERFACE,
timeout: 5000,
headers: {
'Content-Type': 'application/json;charset=UTF-8',
},
})
3.2.2 封装拦截器
查看axios源代码会发现axios继承了AxiosInstance接口,而AxiosInstance返回的类型就是Promise,编写一个interceptors方法,将创建好的axios实例,配置传入,完成拦截器配置。
interceptors(instance: AxiosInstance) {
// 请求拦截
instance.interceptors.request.use(
config => {
// 在发送请求之前做些什么
return config;
},
(error: any) => {
// 对请求错误做些什么
return Promise.reject(error)
}
)
// 响应拦截
instance.interceptors.response.use(
(res: any) => {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
let msg = res.data['msg'] || '未知错误,请联系管理员'
switch (code) {
case 401:
msg = '认证失败,无法访问系统资源'
break
//......
case 'default':
msg = '系统未知错误'
break
}
if (code === 200) {
return Promise.resolve(res)
} else {
//ElMessage.error(msg)
return Promise.reject(res)
}
},
(error: any) => {
// 超出 2xx 范围的状态码都会触发该函数
// 对响应错误做点什么
return Promise.reject(error)
}
)
}
3.2.3 封装请求方法
axios继承了AxiosInstance接口,而AxiosInstance返回的类型就是Promise,我们不需要手动创建Promise对象,而是使用axios本身返回的Promise对象
export default function request(options: AxiosRequestConfig) {
// 配置拦截器
interceptors(instance)
return instance(options)
}
调用请求方法获取Promise对象
request({
url: "/sys/...",
method: "post",
}).then((res) => {
console.log(res);
});
});
以上仅提供一种方式,封装 axios 没有一个绝对的标准,只要你的封装可以满足你的项目需求,并且用起来方便,那就是一个好的封装方案。
4.遇到的问题
4.1config.headers的对象可能未定义
4.1.1 原因
这是axios 0.26.1版本的AxiosRequestConfig里面的headers的类型定义:
(property) AxiosRequestConfig<D = any>.headers?: AxiosRequestHeaders | undefined
而早版本版本的AxiosRequestConfig里面的headers的类型定义:
(property) AxiosRequestConfig.headers?: any
先前版本的headers是any类型的,但config.headers确实有可能是undefined类型。用之前版本的axios就不会报错,但如何在这个版本解决报错呢?
4.1.2 解决
用接口类型进行typeScript的类型覆盖:
interface AxiosType extends AxiosRequestConfig {
headers?: any
}
interceptors(instance: AxiosInstance) {
// 请求拦截
instance.interceptors.request.use(
(config: AxiosType )=> {
// 在发送请求之前做些什么
config.headers['Authorization'] = sessionStorage.getItem('Authorization');
return config;
},
(error: any) => {
// 对请求错误做些什么
return Promise.reject(error)
}
)
// 响应拦截
instance.interceptors.response.use(
(res: any) => {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
let msg = res.data['msg'] || '未知错误,请联系管理员'
switch (code) {
case 401:
msg = '认证失败,无法访问系统资源'
break
//......
case 'default':
msg = '系统未知错误'
break
}
if (code === 200) {
return Promise.resolve(res)
} else {
//ElMessage.error(msg)
return Promise.reject(res)
}
},
(error: any) => {
// 超出 2xx 范围的状态码都会触发该函数
// 对响应错误做点什么
return Promise.reject(error)
}
)
}
更多推荐
所有评论(0)