import.meta.env 是 Vite 在构建时静态注入的只读对象,仅暴露以 VITE_ 开头的环境变量,用于安全、灵活、高效地实现多环境配置,但不可在 HTML 中直接使用,也不支持运行时动态访问。

HTML 本身不支持运行时环境判断,所谓“动态切换 API 路径”,实际是靠前端 JS 在加载后读取环境标识、再构造请求地址。硬编码在 <script> 里或用 <meta> 注入配置,都容易出错且无法应对 CDN 缓存、权限隔离、路径拼接等真实问题。
为什么不能直接在 HTML 中用 <meta name="api-base" content="...">
看似省事,但会立刻踩三个坑:
-
content属性值始终是字符串,JSON.parse()遇到未转义双引号、换行或单引号就直接抛SyntaxError - 开发、测试、生产共用同一份 HTML 文件,
<meta>无法按域名、UA 或构建时间动态生成 - 每次改配置都要重新构建 HTML,违背“动态”本意;CI/CD 流水线里加模板渲染反而增加出错概率
Vite 中如何让 import.meta.env.VITE_API_BASE 正确生效
关键不是写对变量名,而是确保它被真正注入并可访问:
- 环境变量必须以
VITE_开头,否则 Vite 不会暴露给客户端代码 -
.env.development和.env.production文件需放在项目根目录,且不能有 BOM 或 UTF-8 编码异常 - 构建命令要显式指定 mode:
npm run build --mode production,否则默认走production,但可能漏加载对应 .env 文件 - 在
index.html中无法直接使用import.meta.env—— 它只在 JS 模块中有效,所以 API 封装必须写在.ts或.js文件里
如何安全构造请求 URL,避免路径拼接错误
别用字符串拼接:`${base}/users/${id}` 容易被恶意 id 注入(如 "123/../admin")。正确做法是交由浏览器原生解析:
立即学习“前端免费学习笔记(深入)”;
- 用
new URL(path, base)构造地址,自动处理末尾斜杠、协议一致性、相对路径补全 - 动态路径参数应通过
URLSearchParams或对象替换占位符,而不是replace() - 所有请求统一加
credentials: 'include'和超时控制,避免部分请求带 Cookie、部分不带
示例:
function request(path, options = {}) {
const url = new URL(path, import.meta.env.VITE_API_BASE);
return fetch(url, {
...options,
credentials: 'include',
signal: AbortSignal.timeout(import.meta.env.VITE_API_TIMEOUT || 8000)
});
}
配置更新了,但旧请求还在发怎么办
这是最容易被忽略的点:环境变量在构建时固化,不是运行时可变的。所谓“动态切换”,只发生在页面首次加载时拉取配置(如 /api/config),之后整个生命周期内 import.meta.env 值不变。
如果真需要运行时切换(比如用户手动切沙盒/生产模式),就不能依赖构建时变量,而要:
- 维护一个全局可变的
window.API_CONFIG对象 - 所有请求函数必须从该对象实时读取
apiBase,而非缓存初始值 - 用
AbortController主动取消仍在进行中的请求,防止新旧路由混用
构建时的环境变量适合部署阶段确定的环境,运行时配置适合用户主动干预场景——两者目的不同,不能混用。



















