一 前言
本文适合刚接触axios或者使用过几次的同学来分享交流一些入门经验,本文同样适用熟悉axios的同学来作为参考手册。
默认你已经看过axios的相关文档:axios文档 GitHub,通过文档了解基础的使用之后,接下来你可以进入正文。
二 正文
axios = Ajax + 异步处理
1.axios的get与post方法传入参数的区别
(1)get
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
(2)post
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
get是放在参数对象的params属性里面,post是直接放在参数对象里面。
2.学会使用axios.create( )创建axios实例
var instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
创建实例的好处:统一(批量)处理request/response
(1)例如你在每次的请求中都要带 cookie, 你或许可以在每个请求中这么写:
axios.get('/user1',{withCredentials:true});
axios.get('/user2',{withCredentials:true});
... ...
但是你也可以这么用:
var instance = axios.create({
withCredentials:true
});
instance.get('/user1').then();
instance.get('/user2').then();
... ...
(2)如果你的多个请求前缀都是相同的,那么你就可以使用baseUrl
bad:
axios.get('http://www.baidu.com/api/city').then();
axios.get('http://www.baidu.com/api/region').then();
axios.get('http://www.baidu.com/api/user').then();
good:
var instance = axios.create({
baseUrl: http://www.baidu.com/api
});
instance.get('/city').then();
instance.get('/region').then();
instance.get('/user').then();
(3)其他方法推荐
设置超时时间:timeout
设置报文头:header
等等
3.功能强大的拦截器:在请求或响应被 then 或 catch 处理前拦截它们
(1)使用与取消
我们可以这么用:
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
建议将拦截器挂在到实例上:
var instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
如果你想在稍后移除拦截器,可以这样:
var myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
(2)注意事项
拦截器可以拦截请求和拦截响应,在请求或响应被 then 或 catch 处理前拦截它们。
它接受两个函数类型的参数,一个是成功请求/返回的函数,一个是失败请求/返回的函数;可以在这些函数里面做一些事情,例如对于401未授权的错误,我们可以重定向到登陆页:
instance.interceptors.response.use(function (res) {
return res;
},function(error){
if (error.response.status === 401) {
login();
return;
}
});
需要记住的是一旦你返回成功,如果没什么事可做,其他的事交给then之后来做,记得返回response/request,不然then接受不到响应。
(3)使用了拦截器处理相关问题,这样就不再需要使用catch来做错误的处理。
4.万恶的拦截器
instance.interceptors.response.use(function (res) {
return res;
},function(error){
if (error.response.status === 401) {
/*一些处理*/
throw error;
}
});
无论是对成功的处理还是对失败的处理,如果拦截器不抛出错误throw error,那么终将还会执行then里面处理请求成功的函数,即使你返回undefined。
所以,建议在错误处理的最后抛出错误!
5.可供参考的二次封装
转载文章链接:https://juejin.im/post/5a293e...
//引入axios
import axios from 'axios'
let cancel ,promiseArr = {}
const CancelToken = axios.CancelToken;
//请求拦截器
axios.interceptors.request.use(config => {
//发起请求时,取消掉当前正在进行的相同请求
if (promiseArr[config.url]) {
promiseArr[config.url]('操作取消')
promiseArr[config.url] = cancel
} else {
promiseArr[config.url] = cancel
}
return config
}, error => {
return Promise.reject(error)
})
//响应拦截器即异常处理
axios.interceptors.response.use(response => {
return response
}, error => {
if (error && error.response) {
switch (error.response.status) {
case 400:
error.message = '错误请求'
break;
case 401:
error.message = '未授权,请重新登录'
break;
case 403:
error.message = '拒绝访问'
break;
case 404:
error.message = '请求错误,未找到该资源'
break;
case 405:
error.message = '请求方法未允许'
break;
case 408:
error.message = '请求超时'
break;
case 500:
error.message = '服务器端出错'
break;
case 501:
error.message = '网络未实现'
break;
case 502:
error.message = '网络错误'
break;
case 503:
error.message = '服务不可用'
break;
case 504:
error.message = '网络超时'
break;
case 505:
error.message = 'http版本不支持该请求'
break;
default:
error.message = `连接错误${error.response.status}`
}
} else {
error.message = "连接到服务器失败"
}
Message.error(error);//Message 一个UI提示组件
return Promise.resolve(error.response)
})
axios.defaults.baseURL = '/api'
//设置默认请求头
axios.defaults.headers = {
'X-Requested-With': 'XMLHttpRequest'
}
axios.defaults.timeout = 10000
export default {
//get请求
get (url,param) {
return new Promise((resolve,reject) => {
axios({
method: 'get',
url,
params: param,
cancelToken: new CancelToken(c => {
cancel = c
})
}).then(res => {
resolve(res)
})
})
},
//post请求
post (url,param) {
return new Promise((resolve,reject) => {
axios({
method: 'post',
url,
data: param,
cancelToken: new CancelToken(c => {
cancel = c
})
}).then(res => {
resolve(res)
})
})
}
}
注意:这段代码中没有创建axios实例,个人觉得创建实例会更方便调用。
根据官方文档,如何取消一个尚未得到响应的请求:
var CancelToken = axios.CancelToken;
var cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// An executor function receives a cancel function as a parameter
cancel = c;
})
});
// cancel the request
cancel();
6.axios 失败重新请求的封装
//在main.js设置全局的请求次数,请求的间隙
axios.defaults.retry = 4;
axios.defaults.retryDelay = 1000;
axios.interceptors.response.use(undefined, function axiosRetryInterceptor(err) {
var config = err.config;
// If config does not exist or the retry option is not set, reject
if (!config || !config.retry) return Promise.reject(err);
// Set the variable for keeping track of the retry count
config.__retryCount = config.__retryCount || 0;
// Check if we've maxed out the total number of retries
if (config.__retryCount >= config.retry) {
// Reject with the error
return Promise.reject(err);
}
// Increase the retry count
config.__retryCount += 1;
// Create new promise to handle exponential backoff
var backoff = new Promise(function (resolve) {
setTimeout(function () {
resolve();
}, config.retryDelay || 1);
});
// Return the promise in which recalls axios to retry the request
return backoff.then(function () {
return axios(config);
});
});
7.更实用的封装
- 通常不需要请求失败之后再重新请求
- 请求失败之后不需要把错误提示的那么详细
- 通常在请求时还伴随加载状态【重要】
示例代码:
// 创建axios实例
const axiosInstance = axios.create({
// timeout: 3000,
// baseURL,
withCredentials: true,
});
// request拦截器
axiosInstance.interceptors.request.use((config) => config,(error) => Promise.reject(error));
axiosInstance.interceptors.response.use((response)=> {
const {data} = response || {data:{}};
return Promise.resolve(data);
}, (error:any) => {
if(error&&error.response){
const {status,statusText=''} = error.response;
// 提示具体接口报错
return Promise.resolve({
code:-1,
message:`${status}-${statusText}`
});
}else{
const response = {
code:-1, // 表示错误的code码
message:'网络连接错误',
}
// 提示“网络连接错误”
return Promise.resolve(response);
}
});
export default axiosInstance;
和上面的参考封装有以下不同之处:
无论服务器返回的请求是成功(200)还是失败(404 500等),都会被resolve,这就会有三点影响:
- resolve的函数需要根据后端response的成功标示(如code为1表示成功,0表示失败)来判断请求是成功还是失败
- 业务逻辑上.then(()=>{})的时候都会走resolve的函数,这样就可以在这个函数里控制loading状态
- 这样就不再需要.catch()
requestData = ()=>{
setLoading(true);
request(params).then((res={})=>{
// 取消loading
setLoading(false);
const {code, data,message=''} = res;
if(code === 1){
// handle success
Message.success('成功!');
}else{
//handle error
Message.error(`获取xxx出错:${message}`);
}
});
}
三 后记
简单的介绍了一些常见事项和基础用法,有更多的内容等待大家去探索,欢迎留言交流~~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。