别在重复封装 Axios 和 Interceptors 了

鉴于我一打开掘金就是一篇 xxx axios xxx 二次封装,以及我工作好几年的情况,有感而发。

真的不要在重复造轮子了,为什么?听我说道。

  1. axios 本身 Api 就足够简单易用,拦截器/适配器足够扩展任何功能。
  2. 擅自封装还会使得原有 Axios 受到影响,增加开发成本和理解成本。
  3. 本身就已经支持 Typescript,你要加 TS 配置的话稍微有点知识就知道能覆盖类型了。

那是不是不用封装

不是,我也没有说让大家不要封装,而是不要在重复封装,过度封装,这些重复工作在我看来就不应该太过于操心。

甚至写 API 方法我认为都是很没有必要的(懒是最佳生产力),我会利用 @hairy/api-generator 生成 api / types。

怎么封装才是最合适

  1. 保留原有库(axios)设计
  2. 可拔插,没有也不影响
  3. 简化配置,可扩展
  4. 功能单一原则

举几个栗子,这里以我自己的工具库 @hairy/axios-bearer 作为示范。

自动解构响应体(data assign response)

我相信大家都有遇到过的情况了把,怎么避免 data.data

由于执行顺序规则 axiosWithAssignResponse 应该最先被调用。

  • 解构所有返回的 data
import axios from 'axios'
import { axiosWithAssignResponse } from '@hairy/axios-bearer'
axiosWithAssignResponse(axios|instance, '*')
// 保证类型正确, 假设你的data是 { code: xxx, message: '...', data: xxx }
module 'axios' { 
    interface AxiosResponse { 
        code?: number
        message?: string
    }
}
复制代码

请求

const { data, code, message, config, ...other } = await axios<string>('xxx')
// data(string) / code(number)...
复制代码
  • 只解构 data
// 假设你的data是 { data: xxx }
axiosWithAssignResponse(axios|instance, ['data'])
// 由于本身类型就自带 data,不需要处理类型
复制代码

请求

const { data } = await axios<string>('xxx')
// typeof data === 'string' >> true
复制代码

自定义响应错误(custom error)

import axios from 'axios'
import { axiosWithCustomError } from '@hairy/axios-bearer'
// 请求响应的 code === 0 将响应拦截为错误
axiosWithCustomError(axios, () => {
    return response.data.code === 0
})
复制代码

请求

try {
    await axios('xxx')
} catch(error) {
    console.log(error.response.data.code) // 0
}
复制代码

请求时携带参数(extra params)

这个请求我就不展示了,相信大部分都能理解

import axios from 'axios'
import { axiosWithExtraParams } from '@hairy/axios-bearer'
// 直接携带(header)
axiosWithExtraParams(axios, { token: '111' }, 'headers')
// 回调携带(header)
const getExtraParams = () => {
    return { token: '111' }
}
axiosWithExtraParams(axios, getExtraParams, 'headers')

// 携带在 params、data
axiosWithExtraParams(axios, { foo: 'xxx' }, 'params')
axiosWithExtraParams(axios, { foo: 'xxx' }, 'data')
复制代码

请求时携带 loading 处理(loading helper)

这个要做还要考虑多个请求等待问题,所以封装成一个处理函数是最为恰当的,避免在多个项目重复写。

请求携带 loading 处理是一个很偷懒的做法,一般来说 UI 比较有追求或者要求质量的情况下是不会大面积采用的。

import axios from 'axios'
import { axiosWithLoadingHelper } from '@hairy/axios'
axiosWithLoadingHelper(
    axios, 
    // custom show
    (config) => {},
    // custom hide
    (config) => {}
)
// use
axios.get('xxx', { loading: true })
// global use
axios.defaults['loading'] = true
复制代码

以这种思路封装一个失败重复请求

这个例子只是描述这种思路,更建议大家使用这个库 axios-retry

const axiosWithErrorRetry = (axios) => {
    axios.interceptors.response.use(() => ...)
}
复制代码

总结

无论什么功能,普遍都能以这种方式扩展,不局限于我所列的这些功能,我列的这些例子只是供大家参考和思考(一种思路),能理解这个思维就行,你也可以直接用我的工具库。

放眼望去,其实很多库都包含这种设计,例如 Vue 的 .use、node 框架的中间件、plugins 系统这种拔插式的插件扩展方法。

无论什么时候,我们都应该要以某种方法来避免代码冗余,而不是遇到什么问题就 copy 代码。当然,我也不想说的太过,但我认为,假如(我说假如)你在这个行业拼搏好几年了,还在琢磨这种细枝末节的东西,没有点累积只会 copy 或者重复造之前写过的功能,那么你真的要好好思考一下。

说起来现在开源社区这么发达,看到发的 axios 文章却都是包一层的所谓通用方案(这就是所谓的流量密码?),真的蛮令人感到深思的...

最后声明:本人战五渣、懒鬼一个,文采也不好,大家轻喷!

猜你喜欢

转载自juejin.im/post/7108713584808427556
今日推荐