本地开发代理配置
本文档介绍如何配置 VitePress 开发服务器的代理,解决开发环境的跨域问题和 API 调用需求。
为什么需要代理?
在开发过程中,前端通常运行在 localhost:5173,而后端 API 可能运行在不同端口或域名:
- 跨域问题:浏览器阻止跨域请求
- Cookie 问题:跨域请求无法携带 Cookie
- 开发便利:统一 API 请求路径
代理可以让开发服务器转发请求到后端,避免跨域问题。
基础配置
简单代理
ts
// docs/.vitepress/config.mts
import { defineConfig } from 'vitepress'
export default defineConfig({
vite: {
server: {
proxy: {
// 将 /api 请求代理到后端
'/api': {
target: 'http://localhost:3000',
changeOrigin: true
}
}
}
}
})配置说明
| 选项 | 说明 |
|---|---|
target | 代理目标地址 |
changeOrigin | 修改请求头中的 Origin 为目标地址 |
rewrite | 重写请求路径 |
secure | 是否验证 SSL 证书 |
ws | 是否代理 WebSocket |
configure | 自定义代理配置 |
路径重写
移除前缀
ts
export default defineConfig({
vite: {
server: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
}
})请求转换:
前端请求: /api/users
代理到: http://localhost:3000/users添加前缀
ts
export default defineConfig({
vite: {
server: {
proxy: {
'/v1': {
target: 'http://api.example.com',
changeOrigin: true,
rewrite: (path) => `/api${path}`
}
}
}
}
})请求转换:
前端请求: /v1/users
代理到: http://api.example.com/api/v1/users多代理配置
不同路径代理到不同目标
ts
export default defineConfig({
vite: {
server: {
proxy: {
// API 服务
'/api': {
target: 'http://localhost:3000',
changeOrigin: true
},
// 认证服务
'/auth': {
target: 'http://localhost:3001',
changeOrigin: true
},
// 静态资源
'/static': {
target: 'http://localhost:3002',
changeOrigin: true
},
// WebSocket
'/ws': {
target: 'ws://localhost:4000',
ws: true
}
}
}
}
})使用正则匹配
ts
export default defineConfig({
vite: {
server: {
proxy: {
// 匹配所有以 /api 开头的请求
'^/api/.*': {
target: 'http://localhost:3000',
changeOrigin: true
}
}
}
}
})高级配置
自定义请求头
ts
export default defineConfig({
vite: {
server: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
configure: (proxy, options) => {
proxy.on('proxyReq', (proxyReq, req, res) => {
// 添加自定义请求头
proxyReq.setHeader('X-Custom-Header', 'value')
})
}
}
}
}
}
})响应拦截
ts
export default defineConfig({
vite: {
server: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
configure: (proxy) => {
proxy.on('proxyRes', (proxyRes, req, res) => {
console.log(`[Proxy] ${req.method} ${req.url} -> ${proxyRes.statusCode}`)
// 修改响应头
proxyRes.headers['x-proxy'] = 'vitepress'
})
}
}
}
}
}
})错误处理
ts
export default defineConfig({
vite: {
server: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
configure: (proxy) => {
proxy.on('error', (err, req, res) => {
console.error('[Proxy Error]', err.message)
// 返回错误响应
if (!res.headersSent) {
res.writeHead(502, { 'Content-Type': 'application/json' })
res.end(JSON.stringify({
error: 'Proxy Error',
message: err.message
}))
}
})
}
}
}
}
}
})HTTPS 代理
代理到 HTTPS 服务
ts
export default defineConfig({
vite: {
server: {
proxy: {
'/api': {
target: 'https://api.example.com',
changeOrigin: true,
secure: true, // 验证 SSL 证书
// 或忽略证书验证(仅开发环境)
// secure: false
}
}
}
}
})开发服务器启用 HTTPS
ts
export default defineConfig({
vite: {
server: {
https: {
key: fs.readFileSync('./cert/key.pem'),
cert: fs.readFileSync('./cert/cert.pem')
},
proxy: {
'/api': {
target: 'https://api.example.com',
changeOrigin: true
}
}
}
}
})使用 mkcert 生成本地证书
bash
# 安装 mkcert
brew install mkcert # macOS
choco install mkcert # Windows
# 安装本地 CA
mkcert -install
# 生成证书
mkcert localhost 127.0.0.1 ::1Cookie 处理
保留 Cookie
ts
export default defineConfig({
vite: {
server: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
// Cookie 域名重写
cookieDomainRewrite: {
'*': '' // 清除域名限制
}
}
}
}
}
})代理 Cookie 示例
ts
export default defineConfig({
vite: {
server: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
configure: (proxy) => {
proxy.on('proxyRes', (proxyRes) => {
const cookies = proxyRes.headers['set-cookie']
if (cookies) {
// 修改 Cookie 属性
proxyRes.headers['set-cookie'] = cookies.map(cookie =>
cookie.replace(/; Secure/gi, '') // 开发环境移除 Secure
)
}
})
}
}
}
}
}
})WebSocket 代理
基础 WebSocket 代理
ts
export default defineConfig({
vite: {
server: {
proxy: {
'/ws': {
target: 'ws://localhost:4000',
ws: true // 启用 WebSocket 代理
}
}
}
}
})前端使用
vue
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const message = ref('')
let socket = null
onMounted(() => {
socket = new WebSocket(`ws://${location.host}/ws`)
socket.onmessage = (event) => {
message.value = event.data
}
})
onUnmounted(() => {
socket?.close()
})
function send(data) {
socket?.send(data)
}
</script>Mock 数据
使用代理拦截实现 Mock
ts
// docs/.vitepress/config.mts
export default defineConfig({
vite: {
server: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
configure: (proxy) => {
proxy.on('proxyReq', (proxyReq, req, res) => {
// Mock 特定接口
if (req.url === '/api/users') {
// 直接返回 Mock 数据
res.writeHead(200, { 'Content-Type': 'application/json' })
res.end(JSON.stringify({
users: [
{ id: 1, name: 'User 1' },
{ id: 2, name: 'User 2' }
]
}))
return
}
})
}
}
}
}
}
})使用 vite-plugin-mock
bash
npm add -D vite-plugin-mock mockjsts
// docs/.vitepress/config.mts
import { viteMockServe } from 'vite-plugin-mock'
export default defineConfig({
vite: {
plugins: [
viteMockServe({
mockPath: 'mock',
enableDevelopment: true
})
]
}
})ts
// mock/user.ts
import { MockMethod } from 'vite-plugin-mock'
export default [
{
url: '/api/users',
method: 'get',
response: () => {
return {
code: 0,
data: [
{ id: 1, name: 'User 1' },
{ id: 2, name: 'User 2' }
]
}
}
}
] as MockMethod[]环境区分
开发/生产环境区分
ts
// docs/.vitepress/config.mts
import { defineConfig, loadEnv } from 'vitepress'
const env = loadEnv('', process.cwd())
const isDev = process.env.NODE_ENV === 'development'
export default defineConfig({
vite: {
server: isDev ? {
proxy: {
'/api': {
target: env.VITE_API_URL || 'http://localhost:3000',
changeOrigin: true
}
}
} : {}
}
})不同环境不同代理
ts
// docs/.vitepress/config.mts
import { defineConfig, loadEnv } from 'vitepress'
const mode = process.env.NODE_ENV || 'development'
const proxyConfig = {
development: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true
}
},
staging: {
'/api': {
target: 'https://staging-api.example.com',
changeOrigin: true
}
}
}
export default defineConfig({
vite: {
server: {
proxy: proxyConfig[mode] || proxyConfig.development
}
}
})调试代理
日志记录
ts
export default defineConfig({
vite: {
server: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
configure: (proxy) => {
proxy.on('proxyReq', (proxyReq, req) => {
console.log(`[Proxy Request] ${req.method} ${req.url}`)
})
proxy.on('proxyRes', (proxyRes, req) => {
console.log(`[Proxy Response] ${req.url} -> ${proxyRes.statusCode}`)
})
proxy.on('error', (err) => {
console.error('[Proxy Error]', err)
})
}
}
}
}
}
})使用 http-proxy-middleware
bash
npm add -D http-proxy-middlewarets
// docs/.vitepress/config.mts
import { createProxyMiddleware } from 'http-proxy-middleware'
export default defineConfig({
vite: {
server: {
proxy: {
'/api': createProxyMiddleware({
target: 'http://localhost:3000',
changeOrigin: true,
on: {
proxyReq: (proxyReq, req) => {
console.log(`[Proxy] ${req.method} ${req.url}`)
}
}
})
}
}
}
})常见问题
Q: 代理不生效?
检查以下几点:
- 路径是否正确匹配
changeOrigin是否设置- 目标服务是否正常运行
ts
// 调试配置
server: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
configure: (proxy) => {
proxy.on('proxyReq', (proxyReq, req) => {
console.log('代理请求:', req.url)
})
}
}
}
}Q: WebSocket 连接失败?
确保:
- 设置
ws: true - 使用正确的 WebSocket 协议(ws:// 或 wss://)
ts
'/ws': {
target: 'ws://localhost:4000',
ws: true,
changeOrigin: true
}Q: Cookie 无法传递?
ts
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
cookieDomainRewrite: {
'*': ''
}
}完整示例
ts
// docs/.vitepress/config.mts
import { defineConfig, loadEnv } from 'vitepress'
import type { ServerOptions } from 'vite'
const env = loadEnv('', process.cwd())
const proxyConfig: ServerOptions['proxy'] = {
// API 代理
'/api': {
target: env.VITE_API_URL || 'http://localhost:3000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
configure: (proxy) => {
// 请求日志
proxy.on('proxyReq', (proxyReq, req) => {
console.log(`[API] ${req.method} ${req.url}`)
})
// 错误处理
proxy.on('error', (err, req, res) => {
console.error('[Proxy Error]', err.message)
if (!res.headersSent) {
res.writeHead(502)
res.end('Proxy Error')
}
})
}
},
// WebSocket 代理
'/ws': {
target: 'ws://localhost:4000',
ws: true
},
// 静态资源代理
'/static': {
target: 'http://localhost:3002',
changeOrigin: true
}
}
export default defineConfig({
vite: {
server: {
port: 5173,
host: true,
proxy: proxyConfig
}
}
})下一步
学习 Markdown 扩展语法 了解更多内容编写技巧。