本地请求成功,发布后却遇到 404 或跨域错误,常常是把开发环境的便利当成了生产环境的能力。Vite 的环境变量和开发代理分别解决配置注入与本地请求转发,需要分开理解。
暴露给前端的配置就是公开信息
在项目根目录创建 .env.development,放入浏览器可以知道的配置。默认情况下,自定义变量只有使用 VITE_ 前缀才会暴露给客户端源码:
VITE_API_BASE=/api
VITE_ENABLE_SEARCH=true
VITE_PAGE_SIZE=12在代码中通过 import.meta.env.VITE_API_BASE 读取。Vite 会在生产构建中替换这些值,浏览器最终拿到的是包含配置的产物。因此,不要把数据库密码、私钥或服务端 API 密钥放进 VITE_ 变量。前缀是一条暴露规则,不是加密措施。
即使配置来自托管平台的“环境变量”页面,只要被注入客户端构建,也可能出现在公开文件中。需要保密的凭据应留在后端,由后端执行需要凭据的操作。
自定义变量按字符串处理
环境文件中的 true 和 12 都是字符串。Boolean('false') 依然是 true,直接用它做功能开关会得到意外结果。显式比较并校验数值,可以让默认行为更清楚:
const searchEnabled = import.meta.env.VITE_ENABLE_SEARCH === 'true'
const rawPageSize = Number(import.meta.env.VITE_PAGE_SIZE)
const pageSize = Number.isInteger(rawPageSize) && rawPageSize > 0
? rawPageSize
: 12
const apiBase = (import.meta.env.VITE_API_BASE || '/api').replace(/\/$/, '')
const url = `${apiBase}/articles?pageSize=${pageSize}`内置的 import.meta.env.DEV、PROD 和 SSR 是布尔值,别把它们与自定义变量混为一谈。修改 .env 后,需要重启开发服务器。对已发布的静态站点,更改构建变量通常需要重新构建并部署,现有 JavaScript 文件不会自己更新。
默认开发模式会读取 development 模式文件,普通 vite build 使用 production 模式。可以用 vite build --mode staging 读取 .env.staging,但 mode 与 NODE_ENV 是不同概念,不能仅凭模式名称判断是否采用开发构建行为。
server.proxy 只配置开发转发
假设本地后端监听 http://localhost:8080,接口路径本身以 /api 开头。开发服务器可以把浏览器发给同源 /api 的请求转发过去:
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
},
},
},
})这个配置保留 /api 前缀:/api/articles 会转发到后端的同名路径。只有后端实际不带这个前缀时,才需要添加重写规则。前端使用 fetch('/api/articles') 才会经过该代理;直接访问另一域名的绝对地址不会走这里。
changeOrigin 调整代理请求的 Host 等相关行为,不会替线上浏览器配置跨域权限。server.proxy 也不会作为后端能力写进 dist;即使本地预览有相应转发配置,静态托管平台仍需自己的配置。
生产环境选择一种完整方案
可以在同一域名下由服务器、Cloudflare Worker 或平台规则把 /api 转到后端;也可以把公开 API 地址配置为另一个 HTTPS 域名,由 API 服务设置适当的 CORS。涉及 Cookie 时,还要一并考虑凭据模式、允许来源与 Cookie 属性。
上线后从网络面板检查请求最终发往哪里、返回状态码以及响应内容。拿到 HTML 的“接口响应”通常意味着请求被静态站点入口回退接住了,应先检查路由和代理规则,而不是继续改前端 JSON 解析代码。
继续阅读:Vite 环境变量与模式与开发服务器代理。
读到这里,不妨动手试一试。
把一个概念变成能运行的小实验。