axios之基本封装
1. axios实例
安装axios库 npm install axios
or yarn add axios
or CDN <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
// 引入
import axios from 'axios' // 库
import Cookies from 'js-cookie'
import { Notification, MessageBox, Message, Loading } from 'element-ui'
import { getToken } from '@/utils/auth' // 分别暴露
// 创建axios实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout:, // 设置网络超时时间(不同于建立连接超时,而是多久得不到后台的返回数据)
// ...
})
// ...
export default service
2. 请求拦截器
// 请求拦截器
service.interceptors.request.use(
config => {
// 1. 配置用户标识,需要判断本地是否存在 token,每个请求都带上给后端验证 token(失效or过期)
if (getToken()) { // localStorage.sessionId
config.headers['Authorization'] = getToken()
}
// 2.调整请求
// 配置请求头,请求体中的数据会以 json 字符串的形式发送到后端,axios请求类型默认就是这个编码格式,http默认的是application/x-www-form-urlencoded
config.headers['Content-Type'] = '’application/json;charset=utf-8' // 会进行JSON序列化( JS 对象 ==> JSON 字符串 )
// 3. 根据需求添加请求头
if () {
config.headers['xxx'] = Cookies.get('xxx')
}
return config
},
error => {
// 暂时没找到【主动】触发第二个回调的方法
Promise.reject(error)
}
)
auth.js
import Cookies from 'js-cookie'
import Config from '@/settings'
const TokenKey = Config.TokenKey
export function getToken() {
return Cookies.get(TokenKey)
}
2. 响应拦截器的两个函数参数的参数
2.1 response对象的结构
response: {
config:{}, // 请求配置对象
headers:{}, // 响应头
request:{
readyState:4,// 0/1/2/3/4
responseType:'',
status:200,
statusText:''
} // 原生ajax请求对象
statusText:'',
status:200, // 响应状态码,http协议规定
data:{
{
code:0, // 业务状态码,后端约定
data:{},
message:''
}
}, // data 才是后台接口代码中的 return 值!
}
2.2 error对象的结构
{
message:'', // 错误信息
code:'', // 网络超时会有这个属性,被设置为ECONNABORTED
response:{}, // 非网络超时才有,响应对象,同上
// ...
}
3. 响应拦截器
// 响应拦截器
service.interceptors.response.use(
response => {
// 只要请求响应的状态码,response.status 为 2xx,即会触发这个回调
// 二进制数据则直接返回
if(response.request.responseType === 'blob' || response.request.responseType === 'arraybuffer'){
return response.data
}
// 注意,如登录:输入的用户密码错误时,请求响应成功,状态码是200,一般是response.data里设置code或success字段,用0/1来表示业务上的成功与否。
// 此处就这样返回,具体业务中就需要每次都逻辑判断code或success的情况
// return response.data
// 此处假设业务状态码的键为code,0为成功、1为失败;业务消息为msg,因为进到这个回调里的肯定是2xx,所以这里处理的是业务or逻辑上的错误
// 怎么感觉没有什么必要啊,不同的业务不是会有不同的处理吗
const { code, msg, data } = response.data || {}
if() {
return Promise.reject('error')
Message.error(msg ? msg : 'xxx')
} else if() {
return Promise.reject('error')
Message.error(msg ? msg : 'xxx')
} else {
return data
}
},
error => {
// 其它情况
if(){
}
// 请求完全得不到响应,如网络超时(timeout)会触发这个回调
// 请求响应的状态码超出2xx,如404、500...会触发这个回调
else {
try {
// 拿到响应状态码
const status = error.response.status
} catch(err) {
// axios中,网络超时(timeout),error 对象只有 code 和 message 属性,因此 error.response.status 会报错,需捕获异常
if(error.code === 'ECONNABORTED' || error.message === "Network Error" || error.message.includes("timeout"){
Message({
message: '网络超时,请稍后重试',
type: 'error',
duration: 3000
})
}
}
let errMsg = '未知错误'
switch(status){
case 401:
errMsg = '未授权,请重新登录'
// 授权错误:登录用户的token无or无效or过期
// 登出用户、跳转至登录页
// ...
break;
case 403:
errMsg = '拒绝访问' // 与用户访问服务器资源权限有关
break;
case 408:
errMsg = '请求超时' // 指的是服务器等候请求时发生超时
break;
case 500:
errMsg = '服务端出错'
break;
case 502:
errMsg = '网关错误'
break;
default:
errMsg = `其它连接错误:${status}`
break;
}
Message.error(errMsg)
}
// 取消请求,如CancelToken,可以用axios.isCancel(err)来判断是否是取消的请求
else if(axios.isCancel(err)) {
// 处理
}
// 请求运行有异常也会进入这里,如故意将headers写错:axios.defaults.headers = '123',或者在request中有语法或解析错误也会进入这里
// ...
// 以上的所有情况都要返回一个reject的Promise
return Promise.reject(error)
}
)
JSON 是 JS 对象的字符串表示法,JS对象转JSON:
JSON.stringify(obj)
,JSON转JS :JSON.parse(text);
也可以用于深拷贝对象
4. 接口调用
// 接口
export function getList(form,id,unitId) {
return request({
url:'',
method:'',
data:form, // post请求的请求体
params:{
id,unitId
}, // 拼接到url path后,参数部分 如:${api_name}/getXXX?id=1&unitId=111
})
}
// 调用
// getList() === > request() 函数执行,可以理解为new Promise了 === > 拦截器相当于链式调用 ==> res接收响应拦截器设置的返回值 data,err接收Promise.reject(error)
getList().then(res => {
console.log(res) // { code:0,data:{},msg:'返回成功!'}
}).catch(err => {
// 响应拦截器 return Promise.reject(error)就会走catch,或者是代码错误(then阶段处理逻辑代码出错也会catch哦)
console.log(err) // 捕获响应拦截器的error对象,一般情况下如果响应拦截器对错误处理进行了封装,可以不捕获异常,除非then回调里可能出现问题~
})
附:Promise.then().catch() 和 第二个回调的区别
主要区别就是:如果在 .then 的第一个函数里抛出的异常,后面的 .catch 能捕获到,而 .then 的第二个函数捕获不到;
- resolve 后的,一定会进入 then 的第一个回调,肯定不会进入 catch
- reject 后的,会先进入 then 中的第二个回调,如果 then 中没有写第二个回调,则进入 catch
- new Promise 时(抛出)的异常,如果 .then 有第二个回调,是会就近捕获的
- then 第一个回调内(抛出)的异常,只有 catch 可以捕获
// 4示例
const p1 = new Promise((resolve, reject) => {
resolve('成功!');
});
p1.then(
(value) => {
console.log(value); // "成功!"
throw new Error('噢,不!');
},
(err) => {
console.log(err.message, 'then2');
}
).catch((e) => {
console.error(e.message, 'catch'); // "噢,不!"
});
// 3示例
const p1 = new Promise((resolve, reject) => {
throw new Error('errrr');
resolve('成功!');
});
p1.then(
(value) => {
console.log(value);
},
(err) => {
console.log(err.message, 'then2'); // errrr then2
}
).catch((e) => {
console.error(e.message, 'catch');
});
附:axios的post请求像get请求一样,不在请求体中携带数据而是在路径中传参
getById(id){
return request({
url:`xxx/getById`,
method: 'get',
params:{
id
}
})
},
params,参数就会出现在 query string paramter 中
data,请求content-type为application/json,请求体见Request Payload
data,请求content-type为application/x-www-form-urlencoded,参数见Form Data