import type { uniappRequestAdapter } from '@alova/adapter-uniapp' import type { IResponse } from './types' import AdapterUniapp from '@alova/adapter-uniapp' import { createAlova } from 'alova' import { createServerTokenAuthentication } from 'alova/client' import VueHook from 'alova/vue' import { useTokenStore } from '@/store/token' import { toLoginPage } from '@/utils/toLoginPage' import { ContentTypeEnum, ResultEnum, ShowMessage } from './tools/enum' // 配置动态Tag export const API_DOMAINS = { DEFAULT: import.meta.env.VITE_SERVER_BASEURL, SECONDARY: import.meta.env.VITE_SERVER_BASEURL_SECONDARY, } // 添加全局标志,防止重复弹窗 let loginModalShown = false /** * 创建请求实例 */ const { onAuthRequired, onResponseRefreshToken } = createServerTokenAuthentication< typeof VueHook, typeof uniappRequestAdapter >({ // 如果下面拦截不到,请使用 refreshTokenOnSuccess by 群友@琛 refreshTokenOnError: { isExpired: (error) => { console.log('error', error) return error.response?.status === ResultEnum.Unauthorized }, handler: async () => { try { // await authLogin(); console.log('拦截token失效') } catch (error) { // 切换到登录页 // toLoginPage({ mode: 'reLaunch' }) console.log('刷新token失败', error) throw error } }, }, }) /** * alova 请求实例 */ const alovaInstance = createAlova({ baseURL: API_DOMAINS.DEFAULT, ...AdapterUniapp(), // timeout: 7000, statesHook: VueHook, cacheFor: null, beforeRequest: (method) => { // 设置默认 Content-Type method.config.headers = { ContentType: method.type === 'POST' ? ContentTypeEnum.FORM_URLENCODED : ContentTypeEnum.JSON, // // #ifndef MP-WEIXIN // responseType: 'json', // // #endif Accept: 'application/json, text/plain, */*', ...method.config.headers, } console.log('method===>', method) const { config } = method const ignoreAuth = !config.meta?.ignoreAuth // 处理认证信息 自行处理认证问题 if (ignoreAuth) { const tokenStore = useTokenStore() const token = tokenStore.validToken // const token = 'getToken()' if (!token) { throw new Error('[请求错误]:未登录') } method.config.headers['X-Access-Token'] = `${token}` method.config.headers.AppType = '7' // method.config.headers.token = token; } const isShowLoading = !!config.meta?.showLoading if (isShowLoading) { const loadingText = config.meta?.loadingText || '' const loadingMask = !!config.meta?.loadingMask uni.showLoading({ title: loadingText, mask: loadingMask, }) } // 处理动态域名 if (config.meta?.domain) { method.baseURL = config.meta.domain console.log('当前域名', method.baseURL) } }, responded: { onSuccess: (response, method) => { const { config } = method const { requestType } = config const { statusCode, data: rawData, errMsg, } = response as UniNamespace.RequestSuccessCallbackResult // 关闭loading const isShowLoading = !!config.meta?.showLoading if (isShowLoading) { uni.hideLoading() } // 处理特殊请求类型(上传/下载) if (requestType === 'upload' || requestType === 'download') { return response } // 特殊处理:返回原始响应 if (config.meta?.returnResponse) { return response } // 处理 HTTP 状态码错误 if (statusCode !== 200) { // 直接处理401错误,跳转到登录页面 if (statusCode === 401) { if (!loginModalShown) { loginModalShown = true uni.showModal({ title: '提示', content: '登录已过期,请重新登录', confirmText: '去登录', cancelText: '回首页', success: ({ confirm, cancel }) => { loginModalShown = false // 重置标志 if (confirm) { toLoginPage({ mode: 'reLaunch' }) } else if (cancel) { uni.reLaunch({ url: '/pages/home/home' }) } }, fail: () => { loginModalShown = false // 重置标志 } }) useTokenStore().cleanToken() } // setTimeout(() => { // toLoginPage({ mode: 'reLaunch' }) // }, 1500) throw new Error('登录已过期') } const errorMessage = ShowMessage(statusCode) || `HTTP请求错误[${statusCode}]` console.error('errorMessage===>', errorMessage) uni.showToast({ title: errorMessage, icon: 'error', }) throw new Error(`${errorMessage}:${errMsg}`) } // 处理业务逻辑错误 const { code, message, result: data } = rawData as IResponse // 0和200当做成功都很普遍,这里直接兼容两者,见 ResultEnum if (code !== ResultEnum.Success0 && code !== ResultEnum.Success200) { if (config.meta?.toast !== false) { uni.showToast({ title: message, icon: 'none', }) } throw new Error(`请求错误[${code}]:${message}`) } // 处理成功响应,返回业务数据 return data }, // 添加网络错误处理 onError: (error, method) => { const { config } = method // 处理网络错误(断网、超时、DNS解析失败等) console.error('网络错误:', error) // 关闭loading const isShowLoading = !!config.meta?.showLoading if (isShowLoading) { uni.hideLoading() } // 避免重复提示 if (error.message?.includes('HTTP请求错误') || error.message?.includes('请求错误[')) { return } let errorMessage = '网络正在迷路中' if (error.message?.includes('timeout')) { errorMessage = '服务器好像睡着了' } uni.showToast({ title: errorMessage, icon: 'error', }) throw new Error(errorMessage) } }, }) export const http = alovaInstance