123 lines
4.3 KiB
TypeScript
123 lines
4.3 KiB
TypeScript
export type ApiEnvironment = 'local' | 'staging' | 'production';
|
|
type MiniProgramVersion = 'develop' | 'trial' | 'release';
|
|
|
|
const LOCAL_BASE_URL = 'http://127.0.0.1:8800/api/v1';
|
|
const STORAGE_KEY = 'doodle_develop_api_environment_v1';
|
|
let selectedEnvironment: ApiEnvironment | undefined;
|
|
let revision = 0;
|
|
|
|
/** 暂时共用本地地址;部署后分别替换 staging/production,真机 local 使用电脑局域网 IP。 */
|
|
export const apiConfig = {
|
|
developmentEnvironment: 'local' as ApiEnvironment,
|
|
localBaseUrl: LOCAL_BASE_URL,
|
|
stagingBaseUrl: LOCAL_BASE_URL,
|
|
productionBaseUrl: LOCAL_BASE_URL,
|
|
timeout: 10000,
|
|
};
|
|
|
|
export const API_ENVIRONMENTS: ApiEnvironment[] = [
|
|
'local',
|
|
'staging',
|
|
'production',
|
|
];
|
|
|
|
export function isApiEnvironment(value: unknown): value is ApiEnvironment {
|
|
return API_ENVIRONMENTS.includes(value as ApiEnvironment);
|
|
}
|
|
|
|
/** 仅开发包读取本机选择;体验、正式及未知包始终连接 production。 */
|
|
export function getApiEnvironment(
|
|
version: string = wx.getAccountInfoSync().miniProgram.envVersion,
|
|
): ApiEnvironment {
|
|
if (version === 'develop' && selectedEnvironment === undefined) {
|
|
try {
|
|
const stored: unknown = wx.getStorageSync(STORAGE_KEY);
|
|
if (isApiEnvironment(stored)) selectedEnvironment = stored;
|
|
} catch {
|
|
/* 无缓存时使用开发默认值。 */
|
|
}
|
|
}
|
|
return version === 'develop'
|
|
? (selectedEnvironment ?? apiConfig.developmentEnvironment)
|
|
: 'production';
|
|
}
|
|
|
|
export function resolveApiConfig(version: MiniProgramVersion | string) {
|
|
return resolveEnvironment(getApiEnvironment(version), version);
|
|
}
|
|
|
|
function resolveEnvironment(environment: ApiEnvironment, version: string) {
|
|
const baseUrl = apiConfig[`${environment}BaseUrl`]
|
|
.trim()
|
|
.replace(/\/+$/, '');
|
|
if (!baseUrl) throw new Error(`请先配置 ${environment} 接口地址`);
|
|
// 用户指定的本机占位地址暂允许 HTTP;实际云端入口仍须使用 HTTPS。
|
|
if (
|
|
!/^https?:\/\/[^/?#\s]+\/api\/v1$/.test(baseUrl) ||
|
|
(environment !== 'local' &&
|
|
!baseUrl.startsWith('https://') &&
|
|
baseUrl !== LOCAL_BASE_URL)
|
|
)
|
|
throw new Error('接口地址配置不正确');
|
|
return {
|
|
environment,
|
|
baseUrl,
|
|
timeout: apiConfig.timeout,
|
|
revision,
|
|
version,
|
|
};
|
|
}
|
|
|
|
export function getApiConfig() {
|
|
const { appId = '', envVersion } = wx.getAccountInfoSync().miniProgram;
|
|
return { ...resolveApiConfig(envVersion), appId };
|
|
}
|
|
|
|
/** 即使三个地址相同也按环境隔离;develop 不与体验/正式包共享业务缓存。 */
|
|
export function apiContextKey(config = getApiConfig()): string {
|
|
const scope = config.version === 'develop' ? 'develop' : 'public';
|
|
return [config.appId, scope, config.environment, config.baseUrl]
|
|
.map(encodeURIComponent)
|
|
.join(':');
|
|
}
|
|
|
|
/** 版本号阻止 A→B→A 后旧 A 请求覆盖当前页面。 */
|
|
export function isCurrentApiConfig(config: ReturnType<typeof getApiConfig>) {
|
|
const current = getApiConfig();
|
|
return (
|
|
config.revision === current.revision &&
|
|
apiContextKey(config) === apiContextKey(current)
|
|
);
|
|
}
|
|
|
|
/** 写入成功后才提交内存选择;配置失败保留原环境,不自动回退。 */
|
|
export function selectApiEnvironment(environment: ApiEnvironment): boolean {
|
|
if (wx.getAccountInfoSync().miniProgram.envVersion !== 'develop')
|
|
throw new Error('仅开发版可切换环境');
|
|
if (!isApiEnvironment(environment)) throw new Error('未知接口环境');
|
|
resolveEnvironment(environment, 'develop');
|
|
if (getApiEnvironment() === environment) return false;
|
|
wx.setStorageSync(STORAGE_KEY, environment);
|
|
selectedEnvironment = environment;
|
|
revision++;
|
|
return true;
|
|
}
|
|
|
|
export function getApiEnvironmentOptions() {
|
|
return API_ENVIRONMENTS.map((environment) => {
|
|
try {
|
|
return {
|
|
environment,
|
|
baseUrl: resolveEnvironment(environment, 'develop').baseUrl,
|
|
available: true,
|
|
};
|
|
} catch {
|
|
return {
|
|
environment,
|
|
baseUrl: '尚未配置有效地址',
|
|
available: false,
|
|
};
|
|
}
|
|
});
|
|
}
|