index.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import axios from 'axios'
  2. import { toast } from 'vue-sonner'
  3. import type { AxiosRequestConfig } from 'axios'
  4. import type {
  5. BaseResponse,
  6. } from '@/types'
  7. // 请求重试配置
  8. const MAX_RETRY_COUNT = 3 // 最大重试次数
  9. const RETRY_DELAY = 1000 // 重试延迟时间(毫秒)
  10. export const BASE_URL = (import.meta.env.DEV && import.meta.env.VITE_OPEN_PROXY) ? '/proxy/' : import.meta.env.VITE_APP_API_BASEURL
  11. export const BASE_CDN_URL = (import.meta.env.DEV && import.meta.env.VITE_OPEN_PROXY) ? '/proxy/' : import.meta.env.VITE_APP_CDN_BASEURL
  12. // 扩展 AxiosRequestConfig 类型
  13. declare module 'axios' {
  14. export interface AxiosRequestConfig {
  15. retry?: boolean
  16. retryCount?: number
  17. }
  18. }
  19. const api = axios.create({
  20. baseURL: BASE_URL,
  21. timeout: 1000 * 60,
  22. responseType: 'json',
  23. headers: {
  24. Accept: 'application/json',
  25. 'Content-Type': 'application/json',
  26. 'AppTag': 'app.anycall'
  27. // 'accessToken': 'rcOBHJ0Hb8h5xgM/CWtNd8RBhA6WS4OPyJcxrxk4xPZtzeh5PtRXVDA7Um0NZA6NQmnbnZgWB0nNPb8iCrneQj4badFveWLrFq4LrySto3pIo/Zg1dJubbwmu3Vr1LCbSYyVIFrrgt9PXiA85kb9g38FSG3KTSi3AEY/UgjLNLBtH2+91YXKEy2KRZV3v75f',
  28. },
  29. })
  30. api.interceptors.request.use(
  31. (request) => {
  32. // 全局拦截请求发送前提交的参数
  33. const userStore = useUserStore()
  34. // 设置请求头
  35. if (request.headers) {
  36. if (userStore.isLogin) {
  37. request.headers.accessToken = userStore.token
  38. // request.headers.adminToken = userStore.token
  39. }
  40. }
  41. // 是否将 POST 请求参数进行字符串化处理
  42. if (request.method === 'post') {
  43. // request.data = qs.stringify(request.data, {
  44. // arrayFormat: 'brackets',
  45. // })
  46. }
  47. return request
  48. },
  49. )
  50. // 处理错误信息的函数
  51. function handleError(error: any) {
  52. if (error.status === 401) {
  53. useUserStore().requestLogout()
  54. throw error
  55. }
  56. let message = error.message
  57. if (message === 'Network Error') {
  58. message = '后端网络故障'
  59. }
  60. else if (message.includes('timeout')) {
  61. message = '接口请求超时'
  62. }
  63. else if (message.includes('Request failed with status code')) {
  64. message = `接口${message.substr(message.length - 3)}异常`
  65. }
  66. toast.error('Error', {
  67. description: message,
  68. })
  69. return Promise.reject(error)
  70. }
  71. api.interceptors.response.use(
  72. (response) => {
  73. /**
  74. * 全局拦截请求发送后返回的数据,如果数据有报错则在这做全局的错误提示
  75. * 假设返回数据格式为:{code: 0, data: 'DiGJfn3jDc6EQ1KoH/ckj8ZN'}
  76. * 规则是当 status 为 0 时表示请求成功,为 -40 时表示接口需要登录或者登录状态失效,需要重新登录
  77. * 请求出错时 error 会返回错误信息
  78. */
  79. const { code, msg } = response.data
  80. console.log(code, msg, 444444)
  81. if(code === -90){
  82. toast.error('Error', {
  83. description: '克隆服务异常,请联系管理员',
  84. })
  85. return Promise.reject(response.data)
  86. }
  87. // if (typeof response.data === 'object') {
  88. // console.log(response.data,3333444)
  89. // if (response.data.status === 1) {
  90. // if (response.data.error !== '') {
  91. // toast.warning('Warning', {
  92. // description: response.data.error,
  93. // })
  94. // return Promise.reject(response.data)
  95. // }
  96. // }
  97. // else {
  98. // // useUserStore().requestLogout()
  99. // }
  100. // return Promise.resolve(response.data)
  101. // }
  102. // 成功状态
  103. if (code === 0) {
  104. return Promise.resolve(response.data)
  105. }
  106. handleErrorCode(code, msg)
  107. return Promise.reject(response.data)
  108. },
  109. async (error) => {
  110. // 获取请求配置
  111. const config = error.config
  112. // 如果配置不存在或未启用重试,则直接处理错误
  113. if (!config || !config.retry) {
  114. return handleError(error)
  115. }
  116. // 设置重试次数
  117. config.retryCount = config.retryCount || 0
  118. // 判断是否超过重试次数
  119. if (config.retryCount >= MAX_RETRY_COUNT) {
  120. return handleError(error)
  121. }
  122. // 重试次数自增
  123. config.retryCount += 1
  124. // 延迟重试
  125. await new Promise(resolve => setTimeout(resolve, RETRY_DELAY))
  126. // 重新发起请求
  127. return api(config)
  128. },
  129. )
  130. // 处理错误 code
  131. async function handleErrorCode(code: number, msg: string) {
  132. console.log('EE', code, msg)
  133. if (code === -94) {
  134. // 登录失效,退出登录
  135. useUserStore().requestLogout()
  136. toast.error('Error', {
  137. description: msg,
  138. })
  139. }
  140. else if (code === -40) {
  141. // 特殊错误,只显示提示
  142. toast.error('Error', {
  143. description: msg,
  144. })
  145. }
  146. else {
  147. // 所有其他业务错误(如 code: -90),只显示错误提示,不退出登录
  148. toast.error('Error', {
  149. description: msg || '请求失败',
  150. })
  151. }
  152. }
  153. export default api
  154. // 封装一个 request 请求,直接返回 BaseResponse
  155. export const request = async <T>(url: string, data?:Record<string,any>, config?: AxiosRequestConfig<any> | undefined)=> {
  156. return await api.post(url, data, config) as BaseResponse<T>
  157. }