用 TypeScript 封装 Axios

想必作为为一名前端工程师,在开发项目的过程中,没少和 Axios 打交道吧。今天我们对 Axios 进行一次封装,让代码更具健壮性。

在 services 文件夹下创建 index.ts 文件。紧接着创建 config 文件夹,定义常量 BASE_URL 和 TIME_OUT。接着在 request 文件夹下对 axios 方法进行封装。

1
2
3
4
5
6
7
8
9
10
// index.ts
import { BASE_URL, TIME_OUT } from './config'
import LYRequest from './request'

const lyRequest = new LYRequest({
baseURL: BASE_URL,
timeout: TIME_OUT,
})

export default lyRequest

在开发项目中,往往开发环境和生产环境所用到的服务器不同,我们要根据所处的环境给 BASE_URL 赋不同的服务器地址。

1
2
3
4
5
6
7
8
9
10
// config -> index.ts
// 区分生产环境
export let BASE_URL = ''
if (import.meta.env.DEV) {
BASE_URL = 'http://codercba.com:1888'
} else {
BASE_URL = 'http://codercba.com:8000/'
}

export const TIME_OUT = 10000

我的项目采用的是 Vite 这个构建工具,它给我们提供了 import 这个方法,在这个方法下有 meta 属性中包含 env 这个环境变量对象,在这里可以这指定 Vite 根据不同的环境做不同的处理。

紧接着对 Axios 进行封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// request -> index.ts
import axios, { type AxiosInstance, type InternalAxiosRequestConfig } from 'axios'
import type { LYRequestConfig } from './type'

class LYRequest {
instance: AxiosInstance

constructor(config: LYRequestConfig) {
this.instance = axios.create(config)

// 全局请求拦截
this.instance.interceptors.request.use(
(config) => {
// 全局请求成功拦截
console.log('全局请求成功拦截')

return config
},
(err) => {
// 全局请求失败拦截
console.log('全局请求失败拦截')

return err
}
)
// 全局响应拦截
this.instance.interceptors.response.use(
(res) => {
console.log('全局响应成功拦截')

return res.data
},
(err) => {
console.log('全局响应失败拦截')
return err
}
)

// 局部请求和响应拦截
this.instance.interceptors.request.use(
config.interceptors?.requestSuccessFn,
config.interceptors?.requestFailureFn
)
this.instance.interceptors.response.use(
config.interceptors?.responseSuccessFn,
config.interceptors?.responseFailureFn
)
}

request<T = any>(config: LYRequestConfig<T>) {
// 单次请求拦截
if (config.interceptors?.requestSuccessFn) {
config = config.interceptors.requestSuccessFn(config as InternalAxiosRequestConfig)
}

return new Promise<T>((resolve, reject) => {
// 单次响应拦截
this.instance
.request<any, T>(config)
.then((res) => {
if (config.interceptors?.responseSuccessFn) {
res = config.interceptors.responseSuccessFn(res)
}
resolve(res)
})
.catch((err) => {
reject(err)
})
})
}

get<T = any>(config: LYRequestConfig<T>) {
return this.request({
...config,
method: 'GET'
})
}

post<T = any>(config: LYRequestConfig<T>) {
return this.request({
...config,
method: 'POST'
})
}
}

export default LYRequest
1
2
3
4
5
6
7
8
9
10
11
12
13
// request -> type.ts 
import type { AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios'

export interface LYInterceptors<T = AxiosResponse> {
requestSuccessFn?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig
requestFailureFn?: (err: any) => any
responseSuccessFn?: (config: T) => T
responseFailureFn?: (err: any) => any
}

export interface LYRequestConfig<T = any> extends AxiosRequestConfig {
interceptors?: LYInterceptors<T>
}

至此对 axios 的封装就告一段落。上面代码我是跟着Coderwhy 一步步写的。让我写我也只能对 Axios 做简单的封装。毕竟 TypeScript 太难了。在对 Axios 封装过程中还大量用到泛型,泛型是 TypeScript 中最难的知识点之一。