useFetchRequest.ts 6.6 KB

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