chore: 补齐 alova 实例,并添加动态域名切换

This commit is contained in:
feige996
2025-06-22 20:00:45 +08:00
committed by mogenle
parent f4f62b4f92
commit b5fd91913a
7 changed files with 211 additions and 35 deletions

View File

@@ -1,37 +1,111 @@
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 { toast } from '@/utils/toast'
import { ContentTypeEnum, ResultEnum, ShowMessage } from './enum'
const baseURL = JSON.parse(__VITE_APP_PROXY__)
? import.meta.env.VITE_APP_PROXY_PREFIX
: import.meta.env.VITE_SERVER_BASEURL
// 配置动态Tag
export const API_DOMAINS = {
DEFAULT: import.meta.env.VITE_SERVER_BASEURL,
SECONDARY: import.meta.env.VITE_API_SECONDARY_URL,
}
// alovaJS 还在整理中有比较熟悉的开发者可以PR一下省得我去摸索
// 主要是下面这个文件的TS整理如何通过泛型传入想要的数据结构得到对应的数据结构
export const http = createAlova({
baseURL,
...AdapterUniapp(),
async responded(res: UniApp.RequestSuccessCallbackResult, method) {
console.log('responded:', method, res)
// 请求成功的拦截器
// 状态码 2xx参考 axios 的设计
const resData = res.data as IResData<any>
if (res.statusCode >= 200 && res.statusCode < 300) {
// 2.1 提取核心数据 res.data
return resData.data
}
else if (res.statusCode === 401) {
// 401错误 -> 清理用户信息,跳转到登录页
// userStore.clearUserInfo()
// uni.navigateTo({ url: '/pages/login/login' })
console.log(res)
throw new Error(resData.msg || '401错误')
}
else {
uni.showToast({
icon: 'none',
title: (resData).msg || '请求错误',
})
throw new Error(resData.msg || '请求错误')
}
/**
* 创建请求实例
*/
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/common/login/index' })
throw error
}
},
},
})
/**
* alova 请求实例
*/
const alovaInstance = createAlova({
baseURL: import.meta.env.VITE_API_BASE_URL,
...AdapterUniapp(),
timeout: 5000,
statesHook: VueHook,
beforeRequest: onAuthRequired((method) => {
// 设置默认 Content-Type
method.config.headers = {
ContentType: ContentTypeEnum.JSON,
Accept: 'application/json, text/plain, */*',
...method.config.headers,
}
const { config } = method
const ignoreAuth = !config.meta?.ignoreAuth
console.log('ignoreAuth===>', ignoreAuth)
// 处理认证信息 自行处理认证问题
if (ignoreAuth) {
const token = 'getToken()'
if (!token) {
throw new Error('[请求错误]:未登录')
}
// method.config.headers.token = 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
// 处理特殊请求类型(上传/下载)
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, message, data } = rawData as IResponse
if (code !== ResultEnum.Success) {
if (config.meta?.toast !== false) {
toast.warning(message)
}
throw new Error(`请求错误[${code}]${message}`)
}
// 处理成功响应,返回业务数据
return data
}),
})
export const http = alovaInstance

66
src/utils/request/enum.ts Normal file
View File

@@ -0,0 +1,66 @@
export enum ResultEnum {
Success = 0, // 成功
Error = 400, // 错误
Unauthorized = 401, // 未授权
Forbidden = 403, // 禁止访问原为forbidden
NotFound = 404, // 未找到原为notFound
MethodNotAllowed = 405, // 方法不允许原为methodNotAllowed
RequestTimeout = 408, // 请求超时原为requestTimeout
InternalServerError = 500, // 服务器错误原为internalServerError
NotImplemented = 501, // 未实现原为notImplemented
BadGateway = 502, // 网关错误原为badGateway
ServiceUnavailable = 503, // 服务不可用原为serviceUnavailable
GatewayTimeout = 504, // 网关超时原为gatewayTimeout
HttpVersionNotSupported = 505, // HTTP版本不支持原为httpVersionNotSupported
}
export enum ContentTypeEnum {
JSON = 'application/json;charset=UTF-8',
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
FORM_DATA = 'multipart/form-data;charset=UTF-8',
}
/**
* 根据状态码,生成对应的错误信息
* @param {number|string} status 状态码
* @returns {string} 错误信息
*/
export function ShowMessage(status: number | string): string {
let message: string
switch (status) {
case 400:
message = '请求错误(400)'
break
case 401:
message = '未授权,请重新登录(401)'
break
case 403:
message = '拒绝访问(403)'
break
case 404:
message = '请求出错(404)'
break
case 408:
message = '请求超时(408)'
break
case 500:
message = '服务器错误(500)'
break
case 501:
message = '服务未实现(501)'
break
case 502:
message = '网络错误(502)'
break
case 503:
message = '服务不可用(503)'
break
case 504:
message = '网络超时(504)'
break
case 505:
message = 'HTTP版本不受支持(505)'
break
default:
message = `连接出错(${status})!`
}
return `${message},请检查网络或联系管理员!`
}

View File

@@ -0,0 +1,22 @@
// 通用响应格式
export interface IResponse<T = any> {
code: number | string
data: T
message: string
status: string | number
}
// 分页请求参数
export interface PageParams {
page: number
pageSize: number
[key: string]: any
}
// 分页响应数据
export interface PageResult<T> {
list: T[]
total: number
page: number
pageSize: number
}