Files
xiaozhi-esp32-server/main/manager-mobile/src/http/request/alova.ts
T

152 lines
4.4 KiB
TypeScript
Raw Normal View History

2025-08-08 13:02:39 +08:00
import type { uniappRequestAdapter } from '@alova/adapter-uniapp'
import type { IResponse } from './types'
import type { Language } from '@/store/lang'
2025-08-08 13:02:39 +08:00
import AdapterUniapp from '@alova/adapter-uniapp'
import { createAlova } from 'alova'
import { createServerTokenAuthentication } from 'alova/client'
import VueHook from 'alova/vue'
import { getEnvBaseUrl } from '@/utils'
2025-08-08 13:02:39 +08:00
import { toast } from '@/utils/toast'
import { ContentTypeEnum, ResultEnum, ShowMessage } from './enum'
// 语言映射, 用于设置 Accept-language 头
const langMap: Record<Language, string> = {
zh_CN: 'zh-CN',
en: 'en',
zh_TW: 'zh-TW',
de: 'de',
vi: 'vi',
pt_BR: 'pt-BR',
}
2025-08-08 13:02:39 +08:00
/**
* 创建请求实例
*/
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(),
2025-08-08 13:02:39 +08:00
...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)
}
2025-08-08 13:02:39 +08:00
// 设置默认 Content-Type
method.config.headers = {
'Content-Type': ContentTypeEnum.JSON,
'Accept': 'application/json, text/plain, */*',
'Accept-language': currentLang,
2025-08-08 13:02:39 +08:00
...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) {
2025-08-08 13:02:39 +08:00
// 跳转到登录页
uni.reLaunch({ url: '/pages/login/index' })
throw new Error('[请求错误]:未登录')
}
// 添加 Authorization 头
method.config.headers.Authorization = `Bearer ${authInfo.token}`
2025-08-08 13:02:39 +08:00
}
// 处理动态域名
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)
}
2025-08-08 13:02:39 +08:00
if (config.meta?.toast !== false) {
toast.warning(msg)
}
throw new Error(`请求错误[${code}]${msg}`)
}
// 处理成功响应,返回业务数据
return data
}),
})
export const http = alovaInstance