在前端项目开发中,通常会同时存在沙盒测试环境和生产环境,两个环境的API地址不同,开发阶段需要频繁切换调用地址。如果每次都手动修改代码中的API配置,不仅效率低下,还可能出现提交代码时忘记改回配置的问题,因此需要实现动态切换沙盒与生产环境API的能力。

基于环境变量的静态配置方案
这是最基础也最常用的方案,通过构建时的环境变量区分不同环境的API地址,构建完成后配置固定,无法在运行时修改。
实现步骤
首先在项目根目录创建不同环境的配置文件,以Vite项目为例,创建.env.sandbox和.env.production两个文件:
# .env.sandbox VITE_API_BASE_URL=https://sandbox-api.ipipp.com
# .env.production VITE_API_BASE_URL=https://api.ipipp.com
然后在项目的API配置文件中读取环境变量,统一导出基础地址:
// src/config/api.js
// 读取环境变量中的API基础地址,设置默认值避免环境变量缺失时报错
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'https://sandbox-api.ipipp.com';
export default {
baseUrl: API_BASE_URL,
// 其他API相关配置
timeout: 10000
};
在封装请求方法时引入该配置即可:
// src/utils/request.js
import apiConfig from '../config/api.js';
const request = (url, options = {}) => {
return fetch(`${apiConfig.baseUrl}${url}`, {
...options,
headers: {
'Content-Type': 'application/json',
...options.headers
}
}).then(res => res.json());
};
export default request;
优缺点分析
- 优点:实现简单,构建时自动注入配置,无需额外运行时逻辑,适合环境固定不需要动态切换的场景
- 缺点:配置在构建时确定,打包后无法修改,如果需要临时切换环境需要重新构建项目
运行时动态切换方案
如果需要在应用运行过程中动态切换沙盒和生产环境API,不需要重新构建项目,可以通过本地存储、配置面板等方式实现。
实现思路
核心思路是将API基础地址的存储和读取逻辑从构建时环境变量改为运行时动态获取,支持用户手动修改配置并持久化保存。
代码实现示例
首先封装一个获取当前API地址的工具方法,优先读取本地存储的配置,没有则使用默认配置:
// src/utils/env.js
const STORAGE_KEY = 'api_env_config';
// 默认环境配置
const defaultConfig = {
sandbox: {
name: '沙盒环境',
baseUrl: 'https://sandbox-api.ipipp.com'
},
production: {
name: '生产环境',
baseUrl: 'https://api.ipipp.com'
}
};
// 获取当前环境配置
export const getCurrentEnvConfig = () => {
try {
const storedConfig = localStorage.getItem(STORAGE_KEY);
if (storedConfig) {
return JSON.parse(storedConfig);
}
} catch (e) {
console.error('读取环境配置失败', e);
}
// 默认返回沙盒环境配置
return defaultConfig.sandbox;
};
// 切换环境配置
export const switchEnv = (envType) => {
const targetConfig = defaultConfig[envType];
if (!targetConfig) {
throw new Error(`不支持的环境类型:${envType}`);
}
localStorage.setItem(STORAGE_KEY, JSON.stringify(targetConfig));
// 可选:切换后刷新页面让配置生效
window.location.reload();
};
// 获取所有可选环境列表
export const getEnvList = () => {
return Object.keys(defaultConfig).map(key => ({
type: key,
...defaultConfig[key]
}));
};
修改之前的请求方法,使用动态获取的环境配置:
// src/utils/request.js
import { getCurrentEnvConfig } from './env.js';
const request = (url, options = {}) => {
const currentConfig = getCurrentEnvConfig();
return fetch(`${currentConfig.baseUrl}${url}`, {
...options,
headers: {
'Content-Type': 'application/json',
...options.headers
}
}).then(res => res.json());
};
export default request;
可以添加一个简单的环境切换面板,方便用户操作:
<!-- 环境切换面板组件 -->
<div class="env-switch-panel">
<h4>环境切换</h4>
<ul>
<li v-for="env in envList" :key="env.type" @click="handleSwitch(env.type)">
{{ env.name }}
</li>
</ul>
</div>
<script>
import { getEnvList, switchEnv } from './utils/env.js';
export default {
data() {
return {
envList: []
};
},
mounted() {
this.envList = getEnvList();
},
methods: {
handleSwitch(envType) {
switchEnv(envType);
}
}
};
</script>
优缺点分析
- 优点:运行时可动态切换,无需重新构建项目,方便测试人员快速验证不同环境下的问题
- 缺点:配置存储在本地,用户误操作可能切换到错误环境,生产环境需要做好权限控制避免普通用户修改
不同框架下的适配方案
Vue项目适配
Vue项目可以结合Vuex或Pinia状态管理库存储环境配置,避免每次都读取本地存储:
// Pinia 环境配置 store
import { defineStore } from 'pinia';
import { getCurrentEnvConfig, switchEnv as switchEnvUtil } from '../utils/env.js';
export const useEnvStore = defineStore('env', {
state: () => ({
currentEnv: getCurrentEnvConfig()
}),
actions: {
switchEnv(envType) {
switchEnvUtil(envType);
this.currentEnv = getCurrentEnvConfig();
}
}
});
React项目适配
React项目可以使用useContext或状态管理库存储环境配置,在顶层组件提供环境上下文:
// 环境上下文
import React, { createContext, useContext, useState, useEffect } from 'react';
import { getCurrentEnvConfig, switchEnv as switchEnvUtil, getEnvList } from '../utils/env.js';
const EnvContext = createContext();
export const EnvProvider = ({ children }) => {
const [currentEnv, setCurrentEnv] = useState(getCurrentEnvConfig());
const [envList, setEnvList] = useState(getEnvList());
const switchEnv = (envType) => {
switchEnvUtil(envType);
setCurrentEnv(getCurrentEnvConfig());
};
return (
<EnvContext.Provider value={{ currentEnv, envList, switchEnv }}>
{children}
</EnvContext.Provider>
);
};
export const useEnv = () => useContext(EnvContext);
注意事项
- 沙盒环境和生产环境的API数据结构需要保持一致,避免切换后出现接口报错
- 生产环境建议隐藏环境切换入口,或者仅对特定权限的账号开放切换能力
- 本地存储的配置需要做好异常处理,避免存储数据损坏导致应用无法正常运行
- 如果API需要携带环境标识,可以在请求头中统一添加当前环境类型,方便后端做区分