import type { uniappRequestAdapter } from '@alova/adapter-uniapp' import type { IResponse } from './types' import type { Language } from '@/store/lang' import AdapterUniapp from '@alova/adapter-uniapp' import { createAlova } from 'alova' import { createServerTokenAuthentication } from 'alova/client' import VueHook from 'alova/vue' import { getEnvBaseUrl } from '@/utils' import { toast } from '@/utils/toast' import { ContentTypeEnum, ResultEnum, ShowMessage } from './enum' // 语言映射, 用于设置 Accept-language 头 const langMap: Record = { zh_CN: 'zh-CN', en: 'en', zh_TW: 'zh-TW', de: 'de', vi: 'vi', pt_BR: 'pt-BR', } /** * 创建请求实例 */ const { onAuthRequired, onResponseRefreshToken } = createServerTokenAuthentication< typeof VueHook, typeof uniappRequestAdapter >({ refreshTokenOnError: { isExpired: (error) => { return error.response?.status === ResultEnum.Unauthorized }, handler: async () => { try { // await authLogin(); } catch (error) { // 切换到登录页 await uni.reLaunch({ url: '/pages/login/index' }) throw error } }, }, }) /** * alova 请求实例 */ const alovaInstance = createAlova({ baseURL: getEnvBaseUrl(), ...AdapterUniapp(), timeout: 5000, statesHook: VueHook, beforeRequest: onAuthRequired((method) => { // h5动态获取最新的 baseURL,确保使用用户设置的服务器地址 const currentBaseUrl = getEnvBaseUrl() if (currentBaseUrl !== method.baseURL) { method.baseURL = currentBaseUrl } // 检查混合内容错误(HTTPS页面请求HTTP接口) const currentProtocol = typeof window !== 'undefined' && window.location.protocol const requestProtocol = method.baseURL?.split(':')[0] const currentLang = langMap[uni.getStorageSync('app_language') as Language || 'zh_CN'] if (currentProtocol === 'https:' && requestProtocol === 'http') { const errorMessage = '无法配置http协议地址,请检查接口地址' throw new Error(errorMessage) } // 设置默认 Content-Type method.config.headers = { 'Content-Type': ContentTypeEnum.JSON, 'Accept': 'application/json, text/plain, */*', 'Accept-language': currentLang, ...method.config.headers, } const { config } = method const ignoreAuth = config.meta?.ignoreAuth console.log('ignoreAuth===>', ignoreAuth) // 处理认证信息 if (!ignoreAuth) { const authInfo = JSON.parse(uni.getStorageSync('token') || '{}') if (!authInfo.token) { // 跳转到登录页 uni.reLaunch({ url: '/pages/login/index' }) throw new Error('[请求错误]:未登录') } // 添加 Authorization 头 method.config.headers.Authorization = `Bearer ${authInfo.token}` } // 处理动态域名 if (config.meta?.domain) { method.baseURL = config.meta.domain console.log('当前域名', method.baseURL) } }), responded: onResponseRefreshToken((response, method) => { const { config } = method const { requestType } = config const { statusCode, data: rawData, errMsg, } = response as UniNamespace.RequestSuccessCallbackResult console.log(response) // 处理特殊请求类型(上传/下载) if (requestType === 'upload' || requestType === 'download') { return response } // 处理 HTTP 状态码错误 if (statusCode !== 200) { const errorMessage = ShowMessage(statusCode) || `HTTP请求错误[${statusCode}]` console.error('errorMessage===>', errorMessage) toast.error(errorMessage) throw new Error(`${errorMessage}:${errMsg}`) } // 处理业务逻辑错误 const { code, msg, data } = rawData as IResponse if (code !== ResultEnum.Success) { // 检查是否为token失效 if (code === ResultEnum.Unauthorized) { // 清除token并跳转到登录页 uni.removeStorageSync('token') uni.reLaunch({ url: '/pages/login/index' }) throw new Error(`请求错误[${code}]:${msg}`) } if (config.meta?.isExposeError) { return Promise.reject(msg) } if (config.meta?.toast !== false) { toast.warning(msg) } throw new Error(`请求错误[${code}]:${msg}`) } // 处理成功响应,返回业务数据 return data }), }) export const http = alovaInstance