资讯专栏INFORMATION COLUMN

axios入门实践

kamushin233 / 3090人阅读

摘要:使用了拦截器处理相关问题,这样就不再需要使用来做错误的处理。万恶的拦截器一些处理无论是对成功的处理还是对失败的处理,如果拦截器不抛出错误,那么终将还会执行里面处理请求成功的函数,即使你返回。

一 前言

本文适合刚接触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:AxiosResponse)=> {
  const {data} = response || {data:{}};
  return Promise.resolve(data);
}, (error:any) => {
  if(error&&error.response){ 
    // 提示具体接口报错
    return Promise.resolve(error.response);
  }else{
    const response = {
      code:1, // 表示错误的code码
      message:"网络连接错误",
    }
    // 提示“网络连接错误”
    return Promise.resolve(response);
  }
});

export default axiosInstance;

和上面的参考封装有以下不同之处:

拦截器里只抛出网络连接失败的错误

无论服务器返回的请求是成功(200)还是失败(404 500等),都会被resolve,这就会有三点影响:

业务逻辑上.then(()=>{})的时候都会走resolve的函数,这样就可以在这个函数里控制loading状态

resolve的函数需要根据后端response的成功标示来判断请求是成功还是失败

这样就不再需要.catch()

三 后记

简单的介绍了一些常见事项和基础用法,有更多的内容等待大家去探索,欢迎留言交流~~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90468.html

相关文章

  • Vue.js 服务端渲染业务入门实践

    摘要:说起,其实早在出现之前,网页就是在服务端渲染的。没有涉及流式渲染组件缓存对的服务端渲染有更深一步的认识,实际在生产环境中的应用可能还需要考虑很多因素。选择的服务端渲染方案,是情理之中的选择,不是对新技术的盲目追捧,而是一切为了需要。 作者:威威(沪江前端开发工程师)本文原创,转载请注明作者及出处。 背景 最近, 产品同学一如往常笑嘻嘻的递来需求文档, 纵使内心万般拒绝, 身体倒是很诚实...

    miya 评论0 收藏0
  • 2017年2月份前端资源分享

    平日学习接触过的网站积累,以每月的形式发布。2017年以前看这个网址:http://www.kancloud.cn/jsfron... 1. Javascript 前端生成好看的二维码 十大经典排序算法(带动图演示) 为什么知乎前端圈普遍认为H5游戏和H5展示的JSer 个人整理和封装的YU.js库|中文详细注释|供新手学习使用 扩展JavaScript语法记录 - 掉坑初期工具 汉字拼音转换...

    lily_wang 评论0 收藏0
  • 2017年2月份前端资源分享

    平日学习接触过的网站积累,以每月的形式发布。2017年以前看这个网址:http://www.kancloud.cn/jsfron... 1. Javascript 前端生成好看的二维码 十大经典排序算法(带动图演示) 为什么知乎前端圈普遍认为H5游戏和H5展示的JSer 个人整理和封装的YU.js库|中文详细注释|供新手学习使用 扩展JavaScript语法记录 - 掉坑初期工具 汉字拼音转换...

    chengjianhua 评论0 收藏0
  • 2017年2月份前端资源分享

    平日学习接触过的网站积累,以每月的形式发布。2017年以前看这个网址:http://www.kancloud.cn/jsfron... 1. Javascript 前端生成好看的二维码 十大经典排序算法(带动图演示) 为什么知乎前端圈普遍认为H5游戏和H5展示的JSer 个人整理和封装的YU.js库|中文详细注释|供新手学习使用 扩展JavaScript语法记录 - 掉坑初期工具 汉字拼音转换...

    Anonymous1 评论0 收藏0
  • 2017年2月份前端资源分享

    平日学习接触过的网站积累,以每月的形式发布。2017年以前看这个网址:http://www.kancloud.cn/jsfron... 1. Javascript 前端生成好看的二维码 十大经典排序算法(带动图演示) 为什么知乎前端圈普遍认为H5游戏和H5展示的JSer 个人整理和封装的YU.js库|中文详细注释|供新手学习使用 扩展JavaScript语法记录 - 掉坑初期工具 汉字拼音转换...

    dreamtecher 评论0 收藏0

发表评论

0条评论

kamushin233

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<