useFetchRequest.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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. // eslint-disable-next-line no-async-promise-executor
  44. return new Promise(async (resolve, reject) => {
  45. await useFetch(url as string, {
  46. default: () => [],
  47. baseURL,
  48. method,
  49. params: { ...params },
  50. headers,
  51. server: opt.server || false,
  52. credentials: 'include',
  53. body: requestBody,
  54. onRequest: ({ request, options }) => {
  55. // console.log('onResponseError--------aaaa:', options)
  56. const userStore = useUserStore()
  57. const { token } = storeToRefs(userStore)
  58. if (token.value) {
  59. options.headers = {
  60. ...opt.headers,
  61. 'Authorization': token.value,
  62. 'X-Access-Token': token.value,
  63. }
  64. }
  65. },
  66. onRequestError: ({ request, options, error }) => {
  67. ElMessage.closeAll()
  68. error
  69. && ElMessage({
  70. message: 'Sorry, The Data Request Failed',
  71. type: 'error',
  72. plain: true,
  73. })
  74. },
  75. // 响应成功+异常处理
  76. onResponse: ({ request, response, options }) => {
  77. // console.log('onResponseError--------1:', request, response, options, opt)
  78. const data = response._data
  79. const { code, result, message } = data
  80. const hasSuccess
  81. = data && Reflect.has(data, 'code') && code === ResultEnum.SUCCESS
  82. if (hasSuccess)
  83. return resolve(result)
  84. let msg = ''
  85. switch (code) {
  86. case ResultEnum.TIMEOUT:
  87. msg = 'Login timeout, please login again.'
  88. // 超时,自动推出
  89. useUserStore().logout()
  90. break
  91. default:
  92. if (message)
  93. msg = message
  94. }
  95. msg && !opt.isForbiddenErrorPrompt
  96. && ElMessage({
  97. message: msg,
  98. type: 'error',
  99. plain: true,
  100. })
  101. return reject(response._data)
  102. },
  103. // 服务错误响应处理
  104. onResponseError: (error: any) => {
  105. const { response, code, message } = error || {}
  106. const msg: string = response?.data?.message ?? ''
  107. const err: string = error?.toString?.() ?? ''
  108. let errMessage = ''
  109. if (code === 'ECONNABORTED' && message.includes('timeout')) {
  110. errMessage
  111. = 'The interface request timed out. Please refresh the page and try again.'
  112. }
  113. if (err?.includes('Network Error')) {
  114. errMessage
  115. = 'The network is abnormal. Please check whether your network connection is normal.'
  116. }
  117. const status = error?.response?.status
  118. switch (status) {
  119. case 400:
  120. errMessage = `${msg}`
  121. break
  122. // 401: Not logged in
  123. case 401:
  124. errMessage = msg || '用户没有权限'
  125. // 被动登出,带redirect地址
  126. useUserStore().logout()
  127. break
  128. case 403:
  129. errMessage = '用户得到授权,但是访问是被禁止的'
  130. break
  131. case 404:
  132. errMessage = '网络请求错误,未找到该资源'
  133. break
  134. case 405:
  135. errMessage = '网络请求错误,请求方法未允许'
  136. break
  137. case 408:
  138. errMessage = '网络请求超时'
  139. break
  140. case 500:
  141. errMessage = '服务器错误,请联系管理员'
  142. break
  143. case 501:
  144. errMessage = '网络未实现'
  145. break
  146. case 502:
  147. errMessage = '网络错误'
  148. break
  149. case 503:
  150. errMessage = '服务器不可用,服务器暂时过载或维护'
  151. break
  152. case 504:
  153. errMessage = '网络超时'
  154. break
  155. case 505:
  156. errMessage = 'http版本不支持该请求'
  157. break
  158. default:
  159. }
  160. if (errMessage) {
  161. ElMessage({
  162. message: errMessage,
  163. type: 'error',
  164. plain: true,
  165. })
  166. }
  167. return reject(error)
  168. },
  169. })
  170. })
  171. }
  172. return {
  173. get: (url: UrlType, params?: any, option?: RequestOptions) => {
  174. return request(url, params, { method: 'GET', ...option })
  175. },
  176. post: (url: UrlType, params?: any, option?: RequestOptions) => {
  177. return request(url, params, { method: 'POST', ...option })
  178. },
  179. put: (url: UrlType, params?: any, option?: RequestOptions) => {
  180. return request(url, params, { method: 'GET', ...option })
  181. },
  182. delete: (url: UrlType, params?: any, option?: RequestOptions) => {
  183. return request(url, params, { method: 'POST', ...option })
  184. },
  185. }
  186. }