目录结构:
    image.png

    1. import type { AxiosRequestConfig, AxiosResponse } from 'axios'
    2. // 封装的拦截器
    3. export interface BMYRequestInterceptors {
    4. requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig
    5. requestInterceptorCatch?: (error: any) => any
    6. // responseInterceptor?: (res: T) => T
    7. responseInterceptor?: <T = AxiosResponse>(config: T) => T
    8. responseInterceptorCatch?: (error: any) => any
    9. }
    10. export interface BMYRequestConfig extends AxiosRequestConfig {
    11. interceptors?: BMYRequestInterceptors
    12. noCancel?: boolean
    13. // showLoading?: boolean
    14. }
    15. // type.ts 取消请求的数组,请求前判断同一url是否存在,存在就取消
    16. export interface CancelRequestSource {
    17. [index: string]: () => void
    18. }
    1. import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'
    2. import Modal from '@/components/Modal'
    3. import router from '@/router'
    4. import i18n from '@/locale'
    5. import Message from '@/components/Message'
    6. import type { AxiosInstance } from 'axios'
    7. import type { BMYRequestInterceptors, BMYRequestConfig, CancelRequestSource } from './type'
    8. class Request {
    9. instance: AxiosInstance
    10. interceptors?: BMYRequestInterceptors
    11. /**
    12. * 存放取消方法的集合
    13. * 在创建请求后将取消请求方法 push 到该集合中
    14. * 封装一个方法,可以取消请求,传入 url: string|string[]
    15. * 在请求之前判断同一URL是否存在,如果存在就取消请求
    16. */
    17. cancelRequestSourceList: CancelRequestSource[] = []
    18. /**
    19. * 请求之前需要将url push到该集合中
    20. * 请求完毕后将url从集合中删除
    21. * 添加在发送请求之前完成,删除在响应之后删除
    22. */
    23. requestUrlList: string[] = []
    24. constructor(config: BMYRequestConfig) {
    25. // 创建 axios 实例
    26. this.instance = axios.create(config)
    27. // 保存基本信息
    28. this.interceptors = config.interceptors
    29. // 全局请求拦截
    30. this.instance.interceptors.request.use(
    31. (res: AxiosRequestConfig) => {
    32. return res
    33. },
    34. (err: any) => err
    35. )
    36. // 拦截器
    37. this.instance.interceptors.request.use(
    38. this.interceptors?.requestInterceptor,
    39. this.interceptors?.requestInterceptorCatch
    40. )
    41. this.instance.interceptors.response.use(
    42. this.interceptors?.responseInterceptor,
    43. this.interceptors?.responseInterceptorCatch
    44. )
    45. // 全局响应拦截器保证最后执行
    46. this.instance.interceptors.response.use(
    47. // 因为我们接口的数据都在res.data下,所以我们直接返回res.data
    48. (res: AxiosResponse) => {
    49. if (res?.data?.code == 200) {
    50. return res.data
    51. } else if ((res as any).code === 'ERR_CANCELED') {
    52. return Promise.reject('ERR_CANCELED')
    53. } else if ((res as any)?.response?.data?.status === 401) {
    54. Modal({
    55. type: 'error',
    56. titleAlign: 'start',
    57. title: i18n.global.t('service.resuest.warning'),
    58. simple: false,
    59. content: i18n.global.t('service.resuest.warningTipInfo'),
    60. onOk: () => {
    61. router.push({ name: 'login' })
    62. }
    63. })
    64. return Promise.reject('需要重新登录')
    65. } else if (res.status == 200) {
    66. return res.data
    67. } else {
    68. Message({
    69. content: (res as any)?.response?.data?.message,
    70. duration: 2 * 1000,
    71. type: 'warning'
    72. })
    73. return Promise.reject('错误')
    74. }
    75. },
    76. (err: any) => {
    77. return err
    78. }
    79. )
    80. }
    81. // index.ts
    82. /**
    83. * @description: 获取指定 url 在 cancelRequestSourceList 中的索引
    84. * @param {string} url
    85. * @returns {number} 索引位置
    86. */
    87. private getSourceIndex(url: string): number {
    88. return this.cancelRequestSourceList?.findIndex((item: CancelRequestSource) => {
    89. return Object.keys(item)[0] === url
    90. }) as number
    91. }
    92. /**
    93. * @description: 删除 requestUrlList 和 cancelRequestSourceList
    94. * @param {string} url
    95. * @returns {*}
    96. */
    97. private delUrl(url: string) {
    98. const urlIndex = this.requestUrlList?.findIndex((u) => u === url)
    99. const sourceIndex = this.getSourceIndex(url)
    100. // 删除url和cancel方法
    101. urlIndex !== -1 && this.requestUrlList?.splice(urlIndex as number, 1)
    102. sourceIndex !== -1 && this.cancelRequestSourceList?.splice(sourceIndex as number, 1)
    103. }
    104. // 取消全部请求
    105. cancelAllRequest() {
    106. this.cancelRequestSourceList?.forEach((source) => {
    107. const key = Object.keys(source)[0]
    108. source[key]()
    109. })
    110. }
    111. // 取消请求
    112. cancelRequest(url: string[] | string) {
    113. if (typeof url === 'string') {
    114. // 取消单个请求
    115. const sourceIndex = this.getSourceIndex(url)
    116. sourceIndex >= 0 && this.cancelRequestSourceList?.[sourceIndex][url]()
    117. } else {
    118. // 存在多个需要取消请求的地址
    119. url.forEach((u) => {
    120. const sourceIndex = this.getSourceIndex(u)
    121. sourceIndex >= 0 && this.cancelRequestSourceList?.[sourceIndex][u]()
    122. })
    123. }
    124. }
    125. request<T>(config: BMYRequestConfig): Promise<T> {
    126. return new Promise((resolve, reject) => {
    127. // 如果我们为单个请求设置拦截器,这里使用单个请求的拦截器
    128. if (config.interceptors?.requestInterceptor) {
    129. config = config.interceptors.requestInterceptor(config)
    130. }
    131. const { url, noCancel } = config
    132. if (url) {
    133. // 取消多余的请求
    134. !noCancel && this.cancelRequest(url)
    135. this.requestUrlList?.push(url)
    136. config.cancelToken = new axios.CancelToken((c) => {
    137. this.cancelRequestSourceList?.push({
    138. [url]: () => {
    139. // console.log(c, c())
    140. c()
    141. return Promise.reject('')
    142. }
    143. })
    144. })
    145. }
    146. this.instance
    147. .request<any, T>(config)
    148. .then((res) => {
    149. // 如果我们为单个响应设置拦截器,这里使用单个响应的拦截器
    150. if (config.interceptors?.responseInterceptor) {
    151. res = config.interceptors.responseInterceptor<T>(res)
    152. }
    153. resolve(res)
    154. })
    155. .catch((err: any) => {
    156. reject(err)
    157. // return err
    158. })
    159. .finally(() => {
    160. url && this.delUrl(url)
    161. })
    162. })
    163. }
    164. get<T = any>(config: BMYRequestConfig): Promise<T> {
    165. return this.request<T>({ ...config, method: 'GET' })
    166. }
    167. post<T = any>(config: BMYRequestConfig): Promise<T> {
    168. return this.request<T>({ ...config, method: 'POST' })
    169. }
    170. delete<T = any>(config: BMYRequestConfig): Promise<T> {
    171. return this.request<T>({ ...config, method: 'DELETE' })
    172. }
    173. put<T = any>(config: BMYRequestConfig): Promise<T> {
    174. return this.request<T>({ ...config, method: 'PUT' })
    175. }
    176. }
    177. export default Request
    1. import Request from './request'
    2. import { localCache } from '@/util'
    3. import type { BMYRequestInterceptors } from './request/type'
    4. const interceptors: BMYRequestInterceptors = {
    5. requestInterceptor: (config) => {
    6. const token = localCache.getCache('token')
    7. if (token) {
    8. config!.headers!.Authorization = `Bearer ${token}`
    9. }
    10. return config
    11. },
    12. requestInterceptorCatch: (err) => {
    13. return err
    14. },
    15. responseInterceptor: (res) => {
    16. return res
    17. },
    18. responseInterceptorCatch: (err) => {
    19. return err
    20. }
    21. }
    22. const baseConfig = {
    23. timeout: 1000 * 60 * 5,
    24. interceptors
    25. }
    26. export const sysRequest = new Request({
    27. ...baseConfig,
    28. baseURL: '/systemcenter/api/banmayu'
    29. })
    30. export const webRequest = new Request({
    31. ...baseConfig,
    32. baseURL: '/elabnoteWeb/api/banmayu'
    33. })
    34. export const materialRequest = new Request({
    35. ...baseConfig,
    36. baseURL: '/material/api/banmayu'
    37. })
    38. export const request = new Request({
    39. ...baseConfig
    40. })
    41. type CancelRequest = {
    42. url: string[] | string
    43. request: InstanceType<typeof Request>
    44. }
    45. // 取消请求
    46. export const cancelRequest = ({ url, request }: CancelRequest) => {
    47. return request.cancelRequest(url)
    48. }
    49. // 取消全部请求
    50. export const cancelAllRequest = (request: InstanceType<typeof Request>) => {
    51. return request.cancelAllRequest()
    52. }