axios 的简易封装

Posted GoldenaArcher

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了axios 的简易封装相关的知识,希望对你有一定的参考价值。

axios 的简易封装

一些简单的封装,主要总结一下 interceptors 的使用。

初步封装

这一步主要是添加 response 的 interceptors,这里只是处理了当状态为 200 时,将直接返回 data.data,这样在其他地方获取数据的时候就不需要进行解构。

在没有用 interceptors 之前,解构确实挺烦的。

base url 这种我就直接放在这里了,不过正常情况下一般都是配置到 dotenv 里面去的,然后根据环境选择对应的 base url 之类的,这里偷懒一下

代码如下:

import axios from 'axios'

const instance = axios.create(
    baseURL: 'https://dummyjson.com/',
    timeout: 1000,
)

instance.interceptors.request.use(req => 
    return req
, err =>  )

instance.interceptors.response.use(res => 
    const  data, status  = res;
    if (status === 200)
        return data;
, err =>  )

export default instance;

这个是 React 部分的代码:

  const fetchProduct = async () => 
    const data = await axios.get('products/1')
    console.log(data);
  

  useEffect(() => 
    fetchProduct()
  , [])

浏览器渲染:

对 CRUD 的封装

CRUD 部分主要还是对 API 调用进行封装,这一块可以根据使用的 UI 库不同进行微调,主要的作用是:

  • 在 API 调用之前使用遮罩显示 loading 状态

  • 在 API 调用结束后关闭遮罩

    loading 状态这一部分可以结合 Redux 或是 RxJS(我们项目目前正在使用的就是 RxJS),亦或者可以直接通过 UI 库完成

  • 返回一个 Promise 让其他地方继续调用

  • 对于错误的处理

这一部分可以做的很多,根据业务需求调整即可。

对于调用方面其实差距并不大,只不过是讲一些可以 centralize 的处理集中到了一个函数去处理,省的到处复制黏贴。

代码如下:

import axios from 'axios'

const instance = axios.create(
    baseURL: 'https://dummyjson.com/',
    timeout: 1000,
)

instance.interceptors.request.use(req => 
    return req
, err =>  )

instance.interceptors.response.use(res => 
    const  data, status  = res;
    if (status === 200)
        return data;
, err =>  )

const request = (url, params, options, method) => 
    // maybe add loading state here
    return new Promise((resolve, reject) => 
        let data;
        if (method === 'get') 
            data =  params ;
         else if (method === 'post') 
            data =  data: params 
        

        instance(
            method,
            url,
            data: 
                firstName: 'Fred',
                lastName: 'Flintstone'
            
        ).then(res => 
            resolve(res);
        ).catch(e => 
            // sent some notification
            console.log(e);
        ).finally(() => 
            // may be remove loading state
        )
    )


export const get = (url, params, options) => 
    return request(url, params, options, 'get')


export default instance;

React 部分其实没有什么很大的变动:

  const fetchProduct = async () => 
    // const data = await axios.get('products/1')
    // console.log(data);
    const data = await get('products/1');
    console.log(data);
  

从结果上来说是看不出来有什么区别的:

三次封装

三次封装主要就是使用一下 interceptors 了。

在这一部分会添加一个 POST 的调用,并且在 interceptors 中判断调用的方法,如果是 POST 或者 PUT 就添加 header。

在 interceptors 中修改 header、token 是一个非常常见的业务逻辑。另外一个处理方法就是在登录之后重新建立一个新的 instance,这两种处理方法都是比较常见的业务情景。

我这里将原本的数组转化成了对象,并且传了两个 success 和 fail 参数,主要是因为我们目前的项目也没有很好的用到 RxJS 的特性(除了 subscribe 之外其他的也没有怎么用……),也没用 Redux,所以很多 callback 的处理就是传俩函数,在 then 和 catch 中进行处理。

如果是使用其他的库,设计好可复用性这种东西,success 和 fail 的存在并不是必须的。

代码如下:

import axios from 'axios'

const instance = axios.create(
    baseURL: 'https://dummyjson.com/',
    timeout: 1000,
)

const METHOD_TYPE = 
    POST: 'post',
    GET: 'GET',
    PUT: 'PUT'


instance.interceptors.request.use(req => 
    const  method  = req;
    if (method === METHOD_TYPE.POST || method === METHOD_TYPE.PUT)
        req.headers = 
            ...req.headers,
            'Content-Type': 'application/json'
        ;

    return req
, err =>  )

instance.interceptors.response.use(res => 
    const  data, status  = res;
    if (status === 200)
        return data;
, err =>  )

const request = (url, params, options, method, success, fail) => 
    // maybe add loading here
    return new Promise((resolve, reject) => 
        let data;
        if (method === METHOD_TYPE.GET) 
            data =  params ;
         else if (method === METHOD_TYPE.POST) 
            data =  data: params 
        

        instance(
            method,
            url,
            data: 
                firstName: 'Fred',
                lastName: 'Flintstone'
            
        ).then(res => 
            success();
            resolve(res);
        ).catch(e => 
            fail()
            // sent some notification
            console.log(e);
        ).finally(() => 
            // may be remove loading state
        )
    )


export const get = ( url, params, options, success, fail ) => 
    return request(url, params, options, METHOD_TYPE.GET, success, fail)


export const post = ( url, params, options, success, fail ) => 
    return request(url, params, options, METHOD_TYPE.POST, success, fail)


export default instance;

React 调用:

  const fetchProduct = async () => 
    // const data = await axios.get('products/1')
    // console.log(data);
    const data = await get(
      url: 'products/1',
      success: () => 
        console.log('get success');
        // set data etc
      ,
      fail: () => 
        console.log('get fail');
      
    );
    console.log(data);

    const postData = await post(
      url: 'products/add', params: 
        title: 'BMW Pencil',
      ,
      success: () => 
        // set data etc
        console.log('post success');
      ,
      fail: () => 
        console.log('post fail');
      
    )
    console.log(postData);
  

这部分截图忘了,基本上就是 GET 和 POST 的两个输出。

最后封装

这一部分就是最近新折腾的取消调用,axios 的官方文档其实给的挺明确的,不过我想太多了……

最后还是试着跑了一下才发现是真的可以成功:

const controller = new AbortController();

instance.interceptors.request.use(req => 
    const  method  = req;
    if (method === METHOD_TYPE.POST || method === METHOD_TYPE.PUT)
        req.headers = 
            ...req.headers,
            'Content-Type': 'application/json'
        ;

    if (method === METHOD_TYPE.POST) 
        return 
            ...req,
            signal: controller.signal
        
    

    return req
, err => )

controller.abort();

这部分的代码中,如果遇到了一些需要放弃调用的情况——如 token 已经过期等,就可以直接在 interceptors 中返回一个 AbortController 的 signal,controller.abort(); 会监听这个 signal,存在的情况下就会取消 API 调用。

cancelToken 已经过期了,官方并不推荐使用。

效果如下:

可以看到 React 组件中的 log 是输出了,但是 React 中并没有拿到任何的返回值。

network 中也可以看到没有 POST 的调用,这就可以说明 axios 在请求发送出去之前就已经将其取消了,而不是在发送出去之后关闭连接通道假装没有收到。

基本上来说比较常见的业务封装就是这些了,比较经常遇到的 cases 也差不多就这些,当然,有比较有意思的业务需求可以提出来一起讨论一下,如果解决方案还挺干净的我也可以存下来当作 boilerplate。

以上是关于axios 的简易封装的主要内容,如果未能解决你的问题,请参考以下文章

简易封装的axios

Element ui+Vue+SSM-简易学生信息管理系统-请求封装

axios简单封装

axios方法封装

axios的封装

Axios 简易教程