赞
踩
https://blog.csdn.net/qq_40128367/article/details/82735310
https://www.mmxiaowu.com/article/589af8cde9be1c5b21ef8e9c

# 为什么要封装
---
## 1)配置通用项
## 2)统一处理请求错误,进行提示
# 请求流程
---

## 请求失败
通常请求失败有两种原因:
### 1)网络问题或代码问题造成的400、500等错误
### 2)请求参数后端不通过验证,由后端抛出的错误
根据不同的后端框架或者程序员又可以分为两种:
一种是直接返回json,用一个特别的code来区别正常请求反悔的数据
```
{
code: -404,
message: '这是错误信息',
data: '',
}
```
另一种是抛出http 404之类的,然后把错误原因放在header里。
### 在组件写调用ajax时,通常都是这么写
```
import axios from 'axios'
axios.post('/user' , {
params: {
firstName: 'Fred',
lastName: 'Flintstone'
}
})
.then(function (response) {
// 处理响应
if(response.data.code === 200){
console.log(response.data)
} else {
// 其中存在后端返回的错误
}
})
.catch(function (error) {
// 网络异常引发的错误或服务器抛出的错误
console.log(error.toString())
});
```
我们知道,一般中大型规模的项目,请求是比较多的,这样导致代码冗余,会越来越臃肿,我们可以**对错误进行预处理。**
## 拦截器做预处理
### 请求时的拦截器
```
axios.interceptors.request.use(config => {
// 这里可以加一些动作, 比如来个进度条开始动作,
NProgress.start()
return config
}, error => {
return Promise.reject(error)
})
```
### 请求后的拦截器
在普通用法中,then()处理响应,catch()处理错误,通过拦截器,可以提前判断,并返回二者之一。
**这里并没有在拦截器中对错误进行处理,而是将响应或者错误返回到get/post请求的结果中,通过链式处理。**
```
axios.interceptors.response.use(function (response) {
// 返回响应时做一些处理
return response;
}, function (error) {
// 当响应异常时做一些处理
// 这里我们把错误信息扶正, 后面就不需要写 catch 了
return Promise.resolve(error.response)
});
```
## 封装get,post方法
封装的get/post方法由3部分组成:

### 基本配置
包括请求方法,基础url,相对url,参数,超时时间,请求头等。
### checkStatus()
链式处理第一步,判断http状态码是否正常,和拦截器一样,请求正常则返回响应,请求异常则返回错误,最后返回结果给checkCode()。
### checkCode()
链式处理第二步,处理上一步的结果,分别处理网络异常,以及后端返回的异常。
## 在组件中引用
注: 使用babel-preset-stage-3才可保证async和await正常使用。
引入封装后的axios
```
import http from '../utils/http'
import api from '../utils/api'
```
使用方法
```
fetchData: async function () {
let params = {
}
const res = await http.get(api.right, params)
if (res.data.success) {
alert('请求成功')
}
}
```
#代码
---
```
/**axios封装
* 请求拦截、相应拦截、错误统一处理
*/
import axios from 'axios';import QS from 'qs';
import { Toast } from 'vant';
import store from '../store/index'
// 环境的切换
if (process.env.NODE_ENV == 'development') {
axios.defaults.baseURL = '/api';
} else if (process.env.NODE_ENV == 'debug') {
axios.defaults.baseURL = '';
} else if (process.env.NODE_ENV == 'production') {
axios.defaults.baseURL = 'http://api.123dailu.com/';
}
// 请求超时时间
axios.defaults.timeout = 10000;
// post请求头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
// 请求拦截器
axios.interceptors.request.use(
config => {
// 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
// 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
const token = store.state.token;
token && (config.headers.Authorization = token);
return config;
},
error => {
return Promise.error(error);
})
// 响应拦截器
axios.interceptors.response.use(
response => {
if (response.status === 200) {
return Promise.resolve(response);
} else {
return Promise.reject(response);
}
},
// 服务器状态码不是200的情况
error => {
if (error.response.status) {
switch (error.response.status) {
// 401: 未登录
// 未登录则跳转登录页面,并携带当前页面的路径
// 在登录成功后返回当前页面,这一步需要在登录页操作。
case 401:
router.replace({
path: '/login',
query: { redirect: router.currentRoute.fullPath }
});
break;
// 403 token过期
// 登录过期对用户进行提示
// 清除本地token和清空vuex中token对象
// 跳转登录页面
case 403:
Toast({
message: '登录过期,请重新登录',
duration: 1000,
forbidClick: true
});
// 清除token
localStorage.removeItem('token');
store.commit('loginSuccess', null);
// 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
setTimeout(() => {
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
});
}, 1000);
break;
// 404请求不存在
case 404:
Toast({
message: '网络请求不存在',
duration: 1500,
forbidClick: true
});
break;
// 其他错误,直接抛出错误提示
default:
Toast({
message: error.response.data.message,
duration: 1500,
forbidClick: true
});
}
return Promise.reject(error.response);
}
}
);
/**
* get方法,对应get请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export function get(url, params){
return new Promise((resolve, reject) =>{
axios.get(url, {
params: params
})
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err.data)
})
});
}
/**
* post方法,对应post请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export function post(url, params) {
return new Promise((resolve, reject) => {
axios.post(url, QS.stringify(params))
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err.data)
})
});
}
```
```
import axios from 'axios'
import qs from 'qs'
import NProgress from 'nprogress'
axios.interceptors.request.use(config => {
NProgress.start()
return config
}, error => {
return Promise.reject(error)
})
axios.interceptors.response.use(response => response, error => Promise.resolve(error.response))
function checkStatus(response) {
NProgress.done()
if (response.status === 200 || response.status === 304) {
return response
}
return {
data: {
code: -404,
message: response.statusText,
data: response.statusText,
}
}
}
function checkCode(res) {
if (res.data.code !== 200) {
alert(res.data.message)
}
return res
}
export default {
post(url, data) {
return axios({
method: 'post',
url,
data: qs.stringify(data),
timeout: 30000,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
}).then(checkStatus).then(checkCode)
},
get(url, params) {
return axios({
method: 'get',
url,
params,
timeout: 30000,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
}).then(checkStatus).then(checkCode)
}
}
```
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。