通过Nginx反向代理配置连接多个后端服务器

基于路径前缀区分 的代理配置方案(替代环境变量前缀方式),这种方案更直观,通过不同的 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>

三、关键配置讲解

  1. 代理规则的核心逻辑

    • '/api1':前端请求的路径前缀,作为代理匹配的标识;
    • target:后端服务的实际地址,代理会将请求转发到这个地址;
    • pathRewrite:路径重写,'^/api1': ''表示去掉请求中的/api1前缀,避免后端接收到带前缀的路径(例如后端接口是/users,而非/api1/users);
    • changeOrigin: true:必须开启,否则后端会收到前端的真实请求源(如localhost:8080),导致跨域拦截。
  2. axios 实例与代理的匹配 axios 实例的baseURL设置为/api1/api2,与代理配置的前缀一致,这样请求会自动触发对应的代理规则。例如:

    • request1.get('/users') → 实际请求 URL 是http://localhost:8080/api1/users → 代理转发到target/users
  3. 生产环境适配 生产环境中,若前端部署在后端同域名下,可去掉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 反向代理,保持路径前缀统一。

这种方案比环境变量前缀方式更直观,适合服务数量固定、路径区分清晰的场景,是前端多后端服务代理的常用最佳实践。

相关推荐
_AaronWong2 小时前
基于 Vue 3 的屏幕音频捕获实现:从原理到实践
前端·vue.js·音视频开发
z***94842 小时前
Linux下安装Nginx服务及systemctl方式管理nginx详情
linux·运维·nginx
默恋~微凉2 小时前
Nginx(十一)——反向代理与负载均衡
运维·nginx·负载均衡
在掘金801103 小时前
vue3中使用medium-zoom
前端·vue.js
可丷乐3 小时前
nginx常用命令
nginx
抱琴_3 小时前
【Vue3】我用 Vue 封装了个 ECharts Hooks,同事看了直接拿去复用
前端·vue.js
老华带你飞3 小时前
社区养老保障|智慧养老|基于springboot+小程序社区养老保障系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·小程序·毕设·社区养老保障
2503_928411564 小时前
11.25 Vue内置组件
前端·javascript·vue.js
木童6624 小时前
Nginx 深度解析:反向代理与负载均衡、后端Tomcat
linux·运维·nginx