useFetchRequest.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /** @format */
  2. // MyRequest.ts
  3. import { ElMessage } from 'element-plus'
  4. import { useFetch, useRequestHeaders, useRuntimeConfig } from '#app'
  5. import { ResultEnum } from '@/enums/httpEnum'
  6. import { useUserStore } from '@/stores/modules/user'
  7. type UrlType =
  8. | string
  9. | Request
  10. | Ref<string | Request>
  11. | (() => string | Request)
  12. export interface RequestOptions {
  13. method?: any
  14. params?: any
  15. headers?: any
  16. server?: boolean
  17. [key: string]: any
  18. }
  19. export function useMyRequest() {
  20. const request = async (
  21. url: UrlType,
  22. params: any,
  23. opt: RequestOptions = {},
  24. ) => {
  25. const headers = useRequestHeaders(['cookie'])
  26. const { apiBase: baseURL } = useRuntimeConfig().public
  27. let { method = (opt?.method || 'GET') as string } = opt
  28. method = method.toUpperCase()
  29. // 处理请求体
  30. let requestBody: any
  31. if (method === 'POST') {
  32. // 如果参数是 FormData 类型(文件上传),直接使用,不要 JSON.stringify
  33. if (params instanceof FormData) {
  34. requestBody = params
  35. // 删除 Content-Type header,让浏览器自动设置正确的 boundary
  36. delete headers['Content-Type']
  37. }
  38. else {
  39. requestBody = JSON.stringify(params)
  40. headers['Content-Type'] = 'application/json'
  41. }
  42. }
  43. const isProduction = process.env.NODE_ENV === 'production'
  44. // eslint-disable-next-line no-async-promise-executor
  45. return new Promise(async (resolve, reject) => {
  46. await useFetch(url as string, {
  47. default: () => [],
  48. baseURL,
  49. method,
  50. params: { ...params },
  51. headers,
  52. server: opt.server || false,
  53. credentials: 'include',
  54. body: requestBody,
  55. onRequest: ({ request, options }) => {
  56. // console.log('onResponseError--------aaaa:', options)
  57. const userStore = useUserStore()
  58. const { token } = storeToRefs(userStore)
  59. if (token.value) {
  60. options.headers = {
  61. ...opt.headers,
  62. 'Authorization': token.value,
  63. 'X-Access-Token': token.value,
  64. }
  65. }
  66. },
  67. onRequestError: ({ request, options, error }) => {
  68. ElMessage.closeAll()
  69. error
  70. && ElMessage({
  71. message: 'Sorry, The Data Request Failed',
  72. type: 'error',
  73. plain: true,
  74. })
  75. },
  76. // 响应成功+异常处理
  77. onResponse: ({ request, response, options }) => {
  78. // console.log('onResponseError--------1:', request, response, options, opt)
  79. const data = response._data
  80. const { code, result, message } = data
  81. const hasSuccess
  82. = data && Reflect.has(data, 'code') && code === ResultEnum.SUCCESS
  83. if (hasSuccess)
  84. return resolve(result)
  85. let msg = ''
  86. switch (code) {
  87. case ResultEnum.TIMEOUT:
  88. msg = 'Login timeout, please login again.'
  89. // 超时,自动推出
  90. useUserStore().logout()
  91. break
  92. default:
  93. if (message)
  94. msg = message
  95. }
  96. msg && !opt.isErrorPrompt
  97. && ElMessage({
  98. message: msg,
  99. type: 'error',
  100. plain: true,
  101. })
  102. return reject(response._data)
  103. },
  104. // 服务错误响应处理
  105. onResponseError: (error: any) => {
  106. const { response, code, message } = error || {}
  107. const msg: string = response?.data?.message ?? ''
  108. const err: string = error?.toString?.() ?? ''
  109. let errMessage = ''
  110. if (code === 'ECONNABORTED' && message.includes('timeout')) {
  111. errMessage
  112. = 'The interface request timed out. Please refresh the page and try again.'
  113. }
  114. if (err?.includes('Network Error')) {
  115. errMessage
  116. = 'The network is abnormal. Please check whether your network connection is normal.'
  117. }
  118. const status = error?.response?.status
  119. switch (status) {
  120. case 400:
  121. errMessage = `${msg}`
  122. break
  123. // 401: Not logged in
  124. case 401:
  125. errMessage = msg || '用户没有权限'
  126. // 被动登出,带redirect地址
  127. useUserStore().logout()
  128. break
  129. case 403:
  130. errMessage = '用户得到授权,但是访问是被禁止的'
  131. break
  132. case 404:
  133. errMessage = '网络请求错误,未找到该资源'
  134. break
  135. case 405:
  136. errMessage = '网络请求错误,请求方法未允许'
  137. break
  138. case 408:
  139. errMessage = '网络请求超时'
  140. break
  141. case 500:
  142. errMessage = '服务器错误,请联系管理员'
  143. break
  144. case 501:
  145. errMessage = '网络未实现'
  146. break
  147. case 502:
  148. errMessage = '网络错误'
  149. break
  150. case 503:
  151. errMessage = '服务器不可用,服务器暂时过载或维护'
  152. break
  153. case 504:
  154. errMessage = '网络超时'
  155. break
  156. case 505:
  157. errMessage = 'http版本不支持该请求'
  158. break
  159. default:
  160. }
  161. if (errMessage) {
  162. ElMessage({
  163. message: errMessage,
  164. type: 'error',
  165. plain: true,
  166. })
  167. }
  168. return reject(error)
  169. },
  170. })
  171. })
  172. }
  173. return {
  174. get: (url: UrlType, params?: any, option?: RequestOptions) => {
  175. return request(url, params, { method: 'GET', ...option })
  176. },
  177. post: (url: UrlType, params?: any, option?: RequestOptions) => {
  178. return request(url, params, { method: 'POST', ...option })
  179. },
  180. put: (url: UrlType, params?: any, option?: RequestOptions) => {
  181. return request(url, params, { method: 'GET', ...option })
  182. },
  183. delete: (url: UrlType, params?: any, option?: RequestOptions) => {
  184. return request(url, params, { method: 'POST', ...option })
  185. },
  186. }
  187. }