文章目錄
目錄
系列文章
文章目錄
前言
參數定義
請求修改
調試與測試
前言
本文介紹了微信小程序中參數統一管理的實現方案。核心內容包括:
1)通過src/config/index.ts文件實現多環境配置管理,自動區分開發/測試/生產環境;
2)實例request.ts中應用
參數定義
建立src/config/index.ts文件
// src/config/index.ts
type EnvFile = 'dev' | 'test' | 'prod'
function getEnv(): EnvFile {
// #ifdef H5
const m = import.meta.env.MODE // vite 環境變量
if (m === 'production') return 'prod'
if (m === 'test' || m === 'gray') return 'test'
return 'dev'
// #endif
// #ifndef H5
const v = uni.getAccountInfoSync().miniProgram.envVersion
if (v === 'release') return 'prod'
if (v === 'trial') return 'test'
return 'dev' // develop / experience
// #endif
}
/* 1. 與環境無關的常量 */
const COMMON = {
TIMEOUT: 15000,
PAGE_SIZE: 20,
MAX_RETRY: 3,
// 任意其他固定值
} as const
/* 2. 與環境有關的差異配置 */
const ENV_CONFIG = {
dev: {
API_BASE_URL: 'http://127.0.0.1:8080',
API_KEY: 'ae139f8f6a8efc2a74a1e852c5cdaa43',
TRACK_URL: 'http://127.0.0.1:8080',
ENABLE_VCONSOLE: true,
},
test: {
API_BASE_URL: 'https://test-api.xxx.com',
API_KEY: 'test-key-123456',
TRACK_URL: 'https://test-track.xxx.com',
ENABLE_VCONSOLE: true,
},
prod: {
API_BASE_URL: 'https://api.xxx.com',
API_KEY: 'prod-key-abcdef',
TRACK_URL: 'https://track.xxx.com',
ENABLE_VCONSOLE: false,
},
} as const
/* 3. 合併後一次性導出 */
export default {
...COMMON,
...ENV_CONFIG[getEnv()],
} as const
作 用:
根據運行平台與構建環境自動選取對應的後端地址、密鑰及功能開關,並統一導出只讀常量供全局使用。
核心思路
1. 先判斷平台
H5:讀取 Vite 注入的 import.meta.env.MODE
小程序:讀取微信/支付寶等宿主提供的 uni.getAccountInfoSync().miniProgram.envVersion
2. 再映射到 3 套環境
dev | test | prod
3. 最後把「與環境無關的常量」+「當前環境變量」合併成單例導出
請求修改
修改src\utils\request.ts文件
import config from '@/src/config/index'
/* 配置 ------------------------------------------------------------------ */
const BASE_URL: string = config.API_BASE_URL //'http://8.130.11.167:8080'// 替換你的後端域名
const API_KEY: string = config.API_KEY
const TIMEOUT = config.TIMEOUT // ms
配置導入説明
1. 配置來源
代碼中所有 BASE_URL / API_KEY / TIMEOUT 等常量均統一從 @/src/config/index 自動讀取。
該文件會根據運行平台(H5 / 小程序)與構建環境(dev / test / prod)動態返回對應的域名、密鑰及功能開關,業務層無需再寫 if/else 判斷環境。
若後台域名或密鑰發生變更,只需修改 src/config/index.ts ,無需逐文件替換。
完整代碼如下:
// 頂部引入
import { toastError } from './toast'
import config from '@/src/config/index'
/* 配置 ------------------------------------------------------------------ */
const BASE_URL: string = config.API_BASE_URL //'http://8.130.11.167:8080'// 替換你的後端域名
const API_KEY: string = config.API_KEY
const TIMEOUT = config.TIMEOUT // ms
/* 類型定義 --------------------------------------------------------------- */
export type Method = 'GET' | 'POST' | 'PUT' | 'DELETE'
export interface RequestOptions<T = any> {
url: string
method?: Method
data?: T
headers?: Record<string, string>
noToken?: boolean // 跳過 token
noBaseURL?: boolean // 跳過 baseURL
timeout?: number
}
// 後端統一返回格式(按你的實際改)
export interface HttpResponse<T = any> {
status_code: number
status:string
message: string
data: T
}
/* 核心請求 --------------------------------------------------------------- */
export function request<R = any>(options: RequestOptions): Promise<HttpResponse<R>> {
console.log(BASE_URL)
console.log(API_KEY)
return new Promise((resolve, reject) => {
const token = uni.getStorageSync('token')
const header: AnyObject = {
'Content-Type': 'application/json; charset=utf-8',
'x-api-key': API_KEY ,//'ae139f8f6a8efc2a74a1e852c5cdaa43',
...options.headers,
}
if (!options.noToken && token) header.Authorization = `Bearer ${token}`
uni.request({
url: options.noBaseURL ? options.url : `${BASE_URL}${options.url}`,
method: options.method || 'GET',
data: options.data || {},
header,
timeout: options.timeout || TIMEOUT,
success: (res) => handleSuccess<R>(res, resolve, reject),
fail: (err) => handleFail(err, reject),
})
})
}
/* 成功處理 --------------------------------------------------------------- */
function handleSuccess<R>(
res: UniApp.RequestSuccessCallbackResult,
resolve: (value: HttpResponse<R>) => void,
reject: (reason?: any) => void,
) {
const { statusCode, data } = res
// 成功區間
if (statusCode >= 200 && statusCode < 300) {
const resp = data as HttpResponse<R>
if (resp.status_code === 200) resolve(resp)
else {
toastError(resp.message)
reject(resp)
}
return
}
// 401 登錄態失效
if (statusCode === 401) {
const detail = (data as any)?.detail || '登錄已過期'
toastError(detail)
uni.clearStorageSync()
uni.reLaunch({ url: '/pages/login/index' })
reject(new Error(detail))
return
}
// 其他 4xx/5xx
if (statusCode >= 300) {
const detail = (data as any)?.detail || `請求失敗(${statusCode})`
toastError(detail)
reject(new Error(detail))
return
}
}
/* 失敗處理 --------------------------------------------------------------- */
function handleFail(err: any, reject: (reason?: any) => void) {
toastError('網絡異常')
reject(err)
}
/* 上傳文件 --------------------------------------------------------------- */
export function upload<R = any>(
url: string,
filePath: string,
formData?: Record<string, any>,
timeout = 30_000,
): Promise<R> {
const token = uni.getStorageSync('token')
return new Promise((resolve, reject) => {
uni.uploadFile({
url: `${BASE_URL}${url}`,
filePath,
name: 'file',
formData,
header: { Authorization: `Bearer ${token}` },
timeout,
success: (res) => {
const data: HttpResponse<R> = JSON.parse(res.data)
if (data.status_code === 0) resolve(data.data)
else {
uni.showToast({ title: data.message || '上傳失敗', icon: 'none' })
reject(data)
}
},
fail: reject,
})
})
}
/* 導出別名(可選)-------------------------------------------------------- */
export const http = {
get<R>(url: string, params?: any, returnData = true) {
return request<R>({ url, data: params }).then(res =>
returnData ? res.data : res
)
},
post<R>(url: string, data?: any, returnData = true) {
return request<R>({ url, method: 'POST', data }).then(res =>
returnData ? res.data : res
)
},
put<R>(url: string, data?: any, returnData = true) {
return request<R>({ url, method: 'PUT', data }).then(res =>
returnData ? res.data : res
)
},
delete<R>(url: string, returnData = true) {
return request<R>({ url, method: 'DELETE' }).then(res =>
returnData ? res.data : res
)
}
}
調試與測試
1.HBuilderX :運行 → 運行至瀏覽器→Chrome
2.啓動後按 F12 打開開發者工具
3.輸入任意不存在的用户名及密碼,觀察登錄接口返回
4.輸入正確的賬號與密碼