基于路径前缀区分 的代理配置方案(替代环境变量前缀方式),这种方案更直观,通过不同的 URL 前缀(如/api1、/api2)直接映射到不同后端服务,无需依赖环境变量前缀拼接。
一、方案核心思路
通过不同的请求路径前缀 (如/api1对应第一个后端服务,/api2对应第二个后端服务),在vue.config.js中配置多规则代理,让前端请求根据前缀自动转发到对应服务器;同时 axios 封装时通过baseURL匹配这些前缀,实现 "路径前缀→代理规则→后端服务" 的映射。
二、完整配置代码
1. vue.config.js 代理配置(关键)
javascript
const { defineConfig } = require('@vue/cli-service');
module.exports = defineConfig({
devServer: {
port: 8080, // 前端项目端口
open: true, // 启动后自动打开浏览器
proxy: {
// 第一个后端服务:前缀 /api1 → 转发到服务器1
'/api1': {
target: process.env.NODE_ENV === 'production'
? 'http://localhost:10011' // 生产环境服务器1地址
: 'http://192.168.0.2:6687', // 开发环境服务器1地址
changeOrigin: true, // 开启跨域代理(必须,解决开发环境跨域)
ws: false, // 不启用WebSocket(根据后端是否需要调整)
pathRewrite: {
'^/api1': '' // 重写路径:去掉请求中的 /api1 前缀
// 例如前端请求 /api1/users → 实际转发到 target/users
},
// logLevel: 'debug' // 可选:开启代理日志,方便调试
},
// 第二个后端服务:前缀 /api2 → 转发到服务器2
'/api2': {
target: 'http://192.168.0.1:6688', // 服务器2地址(开发/生产一致)
changeOrigin: true,
ws: false,
pathRewrite: {
'^/api2': '' // 去掉 /api2 前缀
// 例如前端请求 /api2/orders → 实际转发到 target/orders
}
},
// 原有UReport服务:前缀 /ureport → 转发到对应服务器
'/ureport': {
target: 'http://localhost:8088',
ws: false,
changeOrigin: true,
pathRewrite: {
'^/ureport': '/ureport' // 此处无需去掉前缀,保持原有路径
}
}
},
disableHostCheck: true // 禁用主机检查(解决跨域时的主机校验问题)
}
});
2. axios 封装(适配多前缀代理)
在src/utils/request.js中创建多个 axios 实例,分别对应不同的路径前缀:
javascript
import axios from 'axios';
import { Message, MessageBox } from 'element-ui';
// 通用创建axios实例的方法
function createAxiosInstance(baseURL) {
const service = axios.create({
baseURL: baseURL, // 匹配代理的路径前缀(/api1 或 /api2)
timeout: 5000,
headers: { 'Content-Type': 'application/json;charset=utf-8' }
});
// 请求拦截器:统一添加token等
service.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token');
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
},
(error) => Promise.reject(error)
);
// 响应拦截器:统一处理错误
service.interceptors.response.use(
(response) => {
const res = response.data;
if (res.code !== 200) {
Message.error(res.message || '请求失败');
if (res.code === 401) {
MessageBox.confirm('登录过期,请重新登录', '提示', {
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
localStorage.removeItem('token');
window.location.reload();
});
}
return Promise.reject(res);
}
return res;
},
(error) => {
Message.error(error.message || '服务器错误');
return Promise.reject(error);
}
);
return service;
}
// 实例1:对应 /api1 代理(服务器1)
export const request1 = createAxiosInstance('/api1');
// 实例2:对应 /api2 代理(服务器2)
export const request2 = createAxiosInstance('/api2');
// 实例3:对应 /ureport 代理(UReport服务)
export const requestUreport = createAxiosInstance('/ureport');
export default request1; // 默认导出服务器1的实例
3. API 调用(按服务拆分)
服务器 1 的 API(src/api/server1.js):
javascript
import { request1 } from '@/utils/request';
// 示例:用户相关接口(对应服务器1)
export const userApi = {
getUserList: (params) => request1.get('/users', { params }), // 实际请求 /api1/users → 转发到服务器1/users
getUserDetail: (id) => request1.get(`/users/${id}`), // /api1/users/1 → 服务器1/users/1
createUser: (data) => request1.post('/users', data)
};
服务器 2 的 API(src/api/server2.js):
javascript
import { request2 } from '@/utils/request';
// 示例:订单相关接口(对应服务器2)
export const orderApi = {
getOrderList: (params) => request2.get('/orders', { params }), // /api2/orders → 服务器2/orders
submitOrder: (data) => request2.post('/orders', data),
cancelOrder: (id) => request2.put(`/orders/${id}/cancel`)
};
UReport 的 API(src/api/ureport.js):
javascript
import { requestUreport } from '@/utils/request';
// 示例:报表相关接口
export const reportApi = {
getReportList: () => requestUreport.get('/list'), // /ureport/list → 服务器/ureport/list
getReportDetail: (id) => requestUreport.get(`/detail/${id}`)
};
4. 组件中使用示例
vue
<template>
<div>
<button @click="getServer1Data">获取服务器1数据</button>
<button @click="getServer2Data">获取服务器2数据</button>
</div>
</template>
<script>
import { userApi } from '@/api/server1';
import { orderApi } from '@/api/server2';
export default {
methods: {
async getServer1Data() {
try {
const res = await userApi.getUserList({ page: 1 });
console.log('服务器1用户数据:', res);
} catch (err) {
console.error('请求失败:', err);
}
},
async getServer2Data() {
try {
const res = await orderApi.getOrderList({ status: 'pending' });
console.log('服务器2订单数据:', res);
} catch (err) {
console.error('请求失败:', err);
}
}
}
};
</script>
三、关键配置讲解
-
代理规则的核心逻辑
'/api1':前端请求的路径前缀,作为代理匹配的标识;target:后端服务的实际地址,代理会将请求转发到这个地址;pathRewrite:路径重写,'^/api1': ''表示去掉请求中的/api1前缀,避免后端接收到带前缀的路径(例如后端接口是/users,而非/api1/users);changeOrigin: true:必须开启,否则后端会收到前端的真实请求源(如localhost:8080),导致跨域拦截。
-
axios 实例与代理的匹配 axios 实例的
baseURL设置为/api1或/api2,与代理配置的前缀一致,这样请求会自动触发对应的代理规则。例如:request1.get('/users')→ 实际请求 URL 是http://localhost:8080/api1/users→ 代理转发到target/users。
-
生产环境适配 生产环境中,若前端部署在后端同域名下,可去掉
baseURL的前缀(或改为后端真实路径);若部署在不同域名,需后端配置 CORS 跨域,或通过 Nginx 反向代理替代devServer.proxy(Nginx 配置示例):nginx# Nginx反向代理配置(生产环境) location /api1/ { proxy_pass http://localhost:10011/; # 转发到服务器1 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /api2/ { proxy_pass http://10.37.45.241:6688/; # 转发到服务器2 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }
四、方案优势
- 直观易维护 :通过
/api1、/api2前缀直接区分服务,无需依赖环境变量拼接,代码可读性更高; - 扩展性强 :新增后端服务时,只需在
vue.config.js添加新的代理规则,再创建对应的 axios 实例即可; - 开发 / 生产兼容 :开发环境用
devServer.proxy,生产环境用 Nginx 反向代理,路径前缀保持一致,无需修改业务代码。
总结
- 核心配置 :通过
vue.config.js的多前缀代理规则,配合 axios 实例的baseURL匹配前缀,实现多服务转发; - 关键要点 :
pathRewrite需去掉前缀、changeOrigin必须开启、axios 实例与代理前缀一一对应; - 生产适配 :开发用
devServer.proxy,生产用 Nginx 反向代理,保持路径前缀统一。
这种方案比环境变量前缀方式更直观,适合服务数量固定、路径区分清晰的场景,是前端多后端服务代理的常用最佳实践。