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(config : RequestConfig) : Promise> { 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>((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() 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() } } } }