Files
xiaozhi-user-uniappx/utils/HttpClient.uts
T

184 lines
4.4 KiB
Plaintext

import { ApiResponse, LoadingManager, RequestConfig } from "@/types/HttpClientType.uts"
import { Config } from "@/config.uts"
import { HttpMethod } from "@/enum/HttpMethod"
import { Auth } from "@/utils/Auth.uts"
import { XiaoZhi } from "@/utils/XiaoZhi"
import { Crypto } from "@/utils/crypto.uts"
import { base64Encode, createRsaPair, rsaEncryptText } from "@/uni_modules/laoqianjunzi-crypto"
/**
* HTTP请求客户端
*
* 职责:
* 1. 统一管理网络请求
* 2. 自动注入认证信息
* 3. 统一处理请求参数
* 4. 统一处理响应数据结构
* 5. 管理全局Loading状态
* 6. 统一异常处理
*/
export class HttpClient {
private static instance : HttpClient | null = null
private static encryptHeader = 'encrypt-key';
private static publicKey = '-----BEGIN PUBLIC KEY-----\n' +
Config.VITE_APP_RSA_PUBLIC_KEY +
'\n-----END PUBLIC KEY-----';
/**
* 获取单例实例
*/
static getInstance() : HttpClient {
if (this.instance == null) {
this.instance = new HttpClient()
}
return this.instance!
}
private constructor() { }
/**
* 发起HTTP请求
*
* @param config 请求配置
* @returns 标准响应对象
*/
async request<T>(config : RequestConfig) : Promise<ApiResponse<T>> {
console.log("请求拦截,请求地址:" + config.url)
let url : string = Config.BASE_URL + config.url
let data = config.data ?? null
let header : UTSJSONObject = {}
let method : RequestMethod = (config.method ?? HttpMethod.GET).toString() as RequestMethod
let timeout : number = 60000
let enableQuic : boolean = false
let withCredentials : boolean = false
let firstIpv4 : boolean = false
let enableChunked : boolean = false
/**
* 请求扩展配置
*
* isToken:
* false -> 不携带Token
*
* repeatSubmit:
* false -> 开启重复提交校验
*
* isEncrypt:
* true -> 启用请求参数加密
*/
const isToken = config.headers?.isToken === false
const isRepeatSubmit = config.headers?.repeatSubmit === false
const isEncrypt = config.headers?.isEncrypt === true
/**
* 自动注入身份认证信息
*/
if (Auth.getToken() != "" && !isToken) {
header['Authorization'] = 'Bearer ' + Auth.getToken()
}
/**
* GET请求参数自动拼接至URL
*/
if (config.method == HttpMethod.GET && config.params != null) {
url = Config.BASE_URL + config.url + XiaoZhi.tansParams(config.params as UTSJSONObject)
}
/**
* 防重复提交处理
*
* 仅针对新增、修改类请求生效
*/
if (!isRepeatSubmit && (config.method === HttpMethod.POST || config.method === HttpMethod.PUT)) {
}
/**
* 请求参数加密处理
*/
if (Config.VITE_APP_ENCRYPT) {
if (isEncrypt && (config.method === HttpMethod.POST || config.method === HttpMethod.PUT)) {
// AES密钥
const aesKey = Crypto.generateAesKey();
// Base64(AES_KEY)
const aesKeyBase64 = base64Encode(aesKey)
// RSA加密后的Header值
header[HttpClient.encryptHeader] = rsaEncryptText(HttpClient.publicKey, aesKeyBase64, 'base64')
console.log(header[HttpClient.encryptHeader]);
const requestData = config.data
if (requestData != null) {
data = Crypto.encryptWithAes(requestData, aesKey)
}
}
}
if (config.loading == true) {
LoadingManager.show()
}
console.log("请求拦截,请求地址:" + url)
try {
return await new Promise<ApiResponse<T>>((resolve, reject) => {
uni.request({
url,
method,
data,
header,
timeout,
enableQuic,
withCredentials,
firstIpv4,
enableChunked,
success: (res) => {
const responseData = res["data"] as UTSJSONObject
const apiResponse = new ApiResponse<T>()
if (responseData != null) {
apiResponse.code = (responseData["code"] as number) ?? 0
apiResponse.msg = (responseData["msg"] as string) ?? ""
apiResponse.data = responseData["data"] as T
}
console.log("响应拦截-响应状态码:" + apiResponse.code)
resolve(apiResponse)
},
fail: (err) => {
reject(err)
},
complete: () => { }
})
})
} catch (e) {
/**
* 统一网络异常提示
*/
if (config.showError != false) {
uni.showToast({
title: "网络异常",
icon: "none"
})
}
throw e
} finally {
/**
* 确保Loading状态正确关闭
*/
if (config.loading != false) {
LoadingManager.hide()
}
}
}
}