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 的简易封装的主要内容,如果未能解决你的问题,请参考以下文章