引言
前端开发时浏览器直接请求 https://api.example.com/... 会遇到三座大山:跨域(CORS)、环境地址混乱、后端还没就绪。Vite 的 server.proxy 让 Dev Server 扮演「中间人」:前端只请求同源路径(/api/...),Dev Server 把它转发给真实后端,顺带处理重写、WebSocket 与多个目标。配合本地 Mock,前端可以不依赖后端进度独立开发。本文把代理与联调做成一套标准工作流。
前置:https://plumephp.com/vite-config-guide/(server 配置)、https://plumephp.com/vite-env-production-best-practices/(环境变量)、https://plumephp.com/vite-dev-server-internals/(Dev Server 中间件)。
目录
- 1. 为什么需要开发代理
- 2. server.proxy 基础配置
- 3. 路径重写与转发规则
- 4. changeOrigin 与跨域
- 5. HTTPS 与 wss 代理
- 6. WebSocket 与实时通道
- 7. 本地 Mock 方案
- 8. 多环境配置矩阵
- 9. 联调工作流与故障排查
- 10. 速查表与一句话记忆
- 延伸阅读
1. 为什么需要开发代理
不代理的痛点:
痛点 1:跨域 —— 前端 5173 端口请求 8000 端口后端,CORS 拦截
痛点 2:地址混乱 —— 每人本地后端端口不同,代码里硬编码
痛点 3:后端未就绪 —— 接口 404,前端被阻塞
代理后的形态:
浏览器 ──同源请求 /api/users──► Vite Dev Server ──转发──► http://localhost:8000/users
▲ │
└──── 同源,无 CORS 问题 ─────┘
核心价值:
- 消除跨域:前端所有请求走同源,CORS 只在「测试环境」暴露;
- 统一地址:代码里写
/api/...,后端地址只在配置里; - 多后端切换:dev/staging/prod 指到不同 target。
2. server.proxy 基础配置
// vite.config.ts
export default {
server: {
proxy: {
"/api": {
target: "http://localhost:8000", // 后端地址
changeOrigin: true, // 改写 Host 头(后端视角=正常来源)
},
// 多个后端:不同前缀指不同 target
"/auth": {
target: "http://localhost:9000",
changeOrigin: true,
},
},
},
};
请求 /api/users
→ 转发到 http://localhost:8000/api/users
→ Host 头改为 localhost:8000(changeOrigin)
→ 响应原样返回前端
关键参数:
target:后端地址(http/https/ws 均可);changeOrigin:是否改写请求的 Host 头——后端校验来源时必开;rewrite:转发前改写路径(见下节);secure:后端是自签 HTTPS 时设为false(跳过证书校验)。
3. 路径重写与转发规则
前端 api 前缀与后端实际路径不一致时用 rewrite 剥离:
proxy: {
"/api": {
target: "http://localhost:8000",
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ""), // 剥掉 /api
},
}
请求 /api/users
→ rewrite 后 /users
→ 转发 http://localhost:8000/users
工程决策:剥不剥 /api 取决于后端约定——
后端带前缀:/api/users → target 保留 /api(不 rewrite)
后端不带前缀:/api/users → rewrite 成 /users(前端约定统一前缀)
团队约定:前端统一用 /api 前缀(可预测、可路由),后端按需剥。这样切换真实后端时只改 target,代码不动。
4. changeOrigin 与跨域
changeOrigin 的意义常被忽略:
不 open:请求到后端的 Host 头是 localhost:5173
→ 后端按 Host 校验(如 CORS 白名单/站点鉴权)会拒绝
open:Host 头改写为 target(localhost:8000)
→ 后端视角 = 同站点请求,校验通过
proxy: {
"/api": {
target: "http://localhost:8000",
changeOrigin: true, // 生产/测试环境通常必开
},
}
什么时候不开:本地后端不校验 Host、或需要「伪造 Referer」时,可不开。默认建议 true。
5. HTTPS 与 wss 代理
目标为 HTTPS 时:
proxy: {
"/api": {
target: "https://api.example.com", // HTTPS 目标
changeOrigin: true,
secure: false, // 目标证书自签/内网时跳过校验(生产不要!)
},
}
wss 代理(WebSocket over TLS):target 用 wss://,Vite 会自动升级到 WebSocket 代理:
proxy: {
"/ws": {
target: "wss://localhost:8000", // 或 ws://
ws: true, // 启用 WebSocket 代理
changeOrigin: true,
},
}
工程要点:ws: true 必须显式开启;HTTPS 目标证书问题在本地开发常见,secure: false 是本地折中,切勿复制到生产网关。
6. WebSocket 与实时通道
前端实时功能(聊天/通知/协作)常连 WebSocket。Vite 代理让「同源的 /ws」也能转发后端长连接:
浏览器 ──ws://localhost:5173/ws──► Vite ──► ws://localhost:8000/ws
(HTTP 升级 + 双向转发)
proxy: {
"/ws": {
target: "ws://localhost:8000",
ws: true,
changeOrigin: true,
},
}
注意与 HMR 的关系:Vite 自身的 HMR 也用 WebSocket(/@vite/client),路径不同不会冲突;代理 /ws 只转发业务通道。
工程要点:生产环境 WebSocket 走同源(网关反代)或独立 WSS 域名,与开发代理的路径保持一致(/ws),减少「环境切换」代码分支。
7. 本地 Mock 方案
后端未就绪时,用 Mock 让前端「不被阻塞」:
Mock 方式对比:
□ vite-plugin-mock → 用配置文件模拟接口(dev 专用)
□ 自定义中间件 → configureServer 注入假数据(最灵活)
□ Mock Service Worker(MSW)→ 拦截浏览器请求(真实验证)
// 自定义中间件 Mock(配置无关、纯 JS)
export function mockPlugin(mocks: Record<string, unknown>): Plugin {
return {
name: "local-mock",
configureServer(server) {
server.middlewares.use((req, res, next) => {
const mock = mocks[req.url ?? ""];
if (mock) { res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify(mock)); }
else next();
});
},
};
}
// 开发时用 Mock,联调时关掉
server: {
proxy: isMockEnabled ? {} : { "/api": realBackend },
}
工程要点:Mock 与真实后端同路径、同结构(用同一个契约文件),切开关就能无缝换——避免「Mock 写一套、后端另一套」的割裂。
8. 多环境配置矩阵
不同环境的代理与地址用环境变量区分:
// .env.development / .env.staging / .env.production
// VITE_API_BASE=/api
// VITE_PROXY_TARGET=http://localhost:8000
export default ({ mode }) => {
const isDev = mode === "development";
return {
server: {
proxy: isDev ? {
"/api": {
target: loadEnv(mode, process.cwd()).VITE_PROXY_TARGET,
changeOrigin: true,
},
} : {},
},
build: {
// 生产直接用 VITE_API_BASE(同源/CDN 场景)
rollupOptions: { /* ... */ },
},
};
};
环境矩阵:
dev: proxy → 本地后端 / Mock
staging: proxy 或无 → 预发布后端
prod: 无 proxy,API 走同源/网关/CDN
工程要点:代理是「开发期」基建——生产构建不带 proxy(产物直接请求 API 地址)。环境差异收敛到「环境变量 + mode」判断,代码零分支。
9. 联调工作流与故障排查
前后端联调做成标准流程:
工作流:
1. 契约先行:OpenAPI/接口文档先定(前后端同源)
2. 前端用 Mock 按契约开发
3. 后端就绪 → 切 target 到真实后端
4. 联调验证:真实数据 + 契约校验(response 与 schema 一致)
5. 故障 → 看 proxy 日志/Network 面板定位
代理故障排查:
| 现象 | 可能原因 | 手段 |
|---|---|---|
| 401/403 | changeOrigin 未开 | 开 changeOrigin: true |
| 404 | rewrite 剥错了前缀 | 检查 rewrite 与后端路径 |
| 证书错 | HTTPS 目标证书 | secure: false(本地) |
| WS 连不上 | 忘开 ws: true | 加 ws: true |
| 超时 | target 未启动/防火墙 | curl target 自测后端 |
# 自测代理
curl -v http://localhost:5173/api/users # 看转发后的响应
10. 速查表与一句话记忆
| 问题 | 一句话答案 |
|---|---|
| 为什么要代理 | 消除跨域、统一地址、多后端切换 |
| proxy 关键参数 | target + changeOrigin + rewrite + ws |
| 路径怎么剥 | rewrite: p => p.replace(/^\/api/, "") |
| 跨域 401 怎么办 | 开 changeOrigin: true |
| WS 代理 | target ws:// + ws: true |
| 后端没就绪 | 同路径 Mock(契约一致),开关切换 |
| 生产怎么办 | 不带 proxy,API 走同源/网关 |
一句话记忆:开发代理 = server.proxy(target/changeOrigin/rewrite/ws)+ 同源 Mock + 环境矩阵(dev 代理、prod 直连)——前端请求永远走 /api 同源路径,切换后端只改配置。
延伸阅读
- https://plumephp.com/vite-config-guide/ — server 配置与多环境变量
- https://plumephp.com/vite-dev-server-internals/ — Dev Server 中间件与代理管线
- https://plumephp.com/vite-env-production-best-practices/ — 环境变量与生产构建
- https://plumephp.com/vite-plugin-development/ — configureServer 与自定义中间件
- https://plumephp.com/vite-devtools-debugging/ — 代理与请求故障排查
- Node.js 专题 — 中间件与反向代理原理
- 网络专题 — 反向代理与 API 网关
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。