本项目使用 Vite 的代理功能来解决开发环境的跨域问题。
代理配置在 vite.config.ts 中:
server: {
proxy: {
// 代理所有 /api 开头的请求
"/api": {
target: "http://localhost:8080",
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ""),
},
// 代理系统接口
"/sys": {
target: "http://localhost:8080",
changeOrigin: true,
},
// 代理 WebSocket
"/websocket": {
target: "http://localhost:8080",
changeOrigin: true,
ws: true,
},
},
}
在开发环境中(npm run dev):
http://localhost:3000http://localhost:8080/api、/sys 开头的请求会被代理到后端请求流程:
浏览器请求: http://localhost:3000/sys/user/list
↓
Vite 代理: http://localhost:8080/sys/user/list
↓
后端响应
在生产环境中(npm run build):
请求流程:
浏览器请求: https://api.example.com/sys/user/list
↓
后端响应
.env.development)# 开发环境使用本地后端
VITE_API_BASE_URL=http://localhost:8080
.env.production)# 生产环境使用实际后端地址
VITE_API_BASE_URL=https://api.example.com
/api 路径代理"/api": {
target: "http://localhost:8080",
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ""),
}
作用: 将 /api 前缀去掉后转发
示例:
/api/users/listhttp://localhost:8080/users/list/sys 路径代理"/sys": {
target: "http://localhost:8080",
changeOrigin: true,
}
作用: 保留 /sys 前缀转发
示例:
/sys/user/listhttp://localhost:8080/sys/user/list"/websocket": {
target: "http://localhost:8080",
changeOrigin: true,
ws: true,
}
作用: 代理 WebSocket 连接
原因: 请求路径不匹配代理规则
解决: 确保请求路径以配置的前缀开头(如 /api、/sys)
// ✅ 正确 - 会被代理
http.get("/sys/user/list");
// ❌ 错误 - 不会被代理
http.get("http://localhost:8080/sys/user/list");
原因: changeOrigin 未设置为 true
解决: 确保代理配置中有 changeOrigin: true
"/api": {
target: "http://localhost:8080",
changeOrigin: true, // 必须设置
}
原因: 跨域请求默认不携带 Cookie
解决: 在代理配置中添加 Cookie 相关配置
"/api": {
target: "http://localhost:8080",
changeOrigin: true,
cookieDomainRewrite: "localhost",
}
原因: 后端使用自签名证书
解决: 添加 secure: false
"/api": {
target: "https://localhost:8443",
changeOrigin: true,
secure: false, // 忽略证书验证
}
server: {
proxy: {
// 用户服务
"/api/user": {
target: "http://localhost:8081",
changeOrigin: true,
},
// 订单服务
"/api/order": {
target: "http://localhost:8082",
changeOrigin: true,
},
},
}
import { loadEnv } from "vite";
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), "");
return {
server: {
proxy: {
"/api": {
target: env.VITE_API_BASE_URL,
changeOrigin: true,
},
},
},
};
});
"/api": {
target: "http://localhost:8080",
changeOrigin: true,
configure: (proxy, options) => {
proxy.on("proxyReq", (proxyReq, req, res) => {
console.log("代理请求:", req.method, req.url);
});
proxy.on("proxyRes", (proxyRes, req, res) => {
console.log("代理响应:", proxyRes.statusCode, req.url);
});
},
}
"/api": {
target: "http://localhost:8080",
changeOrigin: true,
rewrite: (path) => {
// 移除 /api 前缀
const newPath = path.replace(/^\/api/, "");
console.log(`重写路径: ${path} -> ${newPath}`);
return newPath;
},
}
生产环境通常使用 Nginx 做反向代理:
server {
listen 80;
server_name example.com;
# 前端静态资源
location / {
root /var/www/html;
try_files $uri $uri/ /index.html;
}
# 后端 API 代理
location /api {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /sys {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
如果前后端部署在不同域名:
前端: https://www.example.com
后端: https://api.example.com
需要在 .env.production 中配置完整的后端地址:
VITE_API_BASE_URL=https://api.example.com
同时后端需要配置 CORS:
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("https://www.example.com");
config.addAllowedMethod("*");
config.addAllowedHeader("*");
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
在 vite.config.ts 中添加日志:
server: {
proxy: {
"/api": {
target: "http://localhost:8080",
changeOrigin: true,
configure: (proxy) => {
proxy.on("error", (err) => {
console.log("代理错误:", err);
});
proxy.on("proxyReq", (proxyReq, req) => {
console.log("发送请求:", req.method, req.url);
});
proxy.on("proxyRes", (proxyRes, req) => {
console.log("收到响应:", proxyRes.statusCode, req.url);
});
},
},
},
}
# 启动开发服务器
pnpm dev
# 在浏览器中访问
http://localhost:3000
# 在控制台测试请求
fetch('/sys/user/list').then(r => r.json()).then(console.log)