【vueconfig-proxy代理解决跨域问题】

代理

前言:在 Vue 项目中,接口请求可以通过 vue.config.js 配置代理,解决跨域问题。
在项目中,嵌入页面中的接口,也是可正常走开发环境代理。

  • 开发环境代理:在 vue.config.js 中的 devServer.proxy 配置只在开发时生效
  • 生产环境:部署后代理配置无效,需要直接请求后端地址,需要其他方案处理跨域。

代理配置的工作原理

vue.config.js 中的代理配置:

javascript 复制代码
// vue.config.js
module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://api.example.com',  // 真实后端地址
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''  // 重写路径,去掉 /api 前缀
        }
      }
    }
  }
}

前端代码中使用:

javascript 复制代码
// 开发环境:请求会被代理到 http://api.example.com
// 生产环境:需要配置正确的 baseURL
methods: {
  async fetchData() {
    // 开发时请求本地 /api/users,会被代理到 http://api.example.com/users
    const response = await axios.get('/api/users');
    
    // 或者直接请求完整路径
   const response2 = await axios.get('http://localhost:8080/api/users');
  }
}

何时会走代理?

开发环境(npm run serve):

  • 请求以 /api 开头的路径
  • 请求的域名与当前开发服务器相同(localhost:8080)
  • 会经过 devServer 的代理配置
javascript 复制代码
// 以下情况会触发代理:
axios.get('/api/users')                    // ✓ 会代理
axios.get('/api/products')                 // ✓ 会代理
axios.get('http://localhost:8080/api/data') // ✓ 会代理

// 以下情况不会走代理:
axios.get('https://api.example.com/data')  // ✗ 直接请求,不走代理
axios.get('/users')                        // ✗ 不以 /api 开头
axios.get('http://other-domain.com/api')  // ✗ 不同域名

生产环境(npm run build):

  • 代理配置不生效
  • 需要直接请求后端真实地址
  • 或者配置生产环境 API 地址

完整的项目配置示例

方案一:环境变量配置

javascript 复制代码
// .env.development
VUE_APP_API_BASE_URL=/api

// .env.production
VUE_APP_API_BASE_URL=https://api.yourdomain.com

// src/utils/request.js
import axios from 'axios';

const request = axios.create({
  baseURL: process.env.VUE_APP_API_BASE_URL,
  timeout: 10000
});

export default request;

// 在组件中使用
import request from '@/utils/request';

methods: {
  async getUsers() {
    // 开发环境:/api/users → 代理到真实后端
    // 生产环境:https://api.yourdomain.com/users
    const response = await request.get('/users');
    return response.data;
  }
}

方案二:动态判断环境

javascript 复制代码
// src/api/index.js
import axios from 'axios';

// 判断当前环境
const isDevelopment = process.env.NODE_ENV === 'development';

const apiClient = axios.create({
  baseURL: isDevelopment ? '/api' : 'https://api.yourdomain.com',
  timeout: 10000
});

// 请求拦截器
apiClient.interceptors.request.use(config => {
  // 可以在这里添加 token 等
  const token = localStorage.getItem('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

export default apiClient;

实践示例

javascript 复制代码
// 1. 创建统一的请求封装
// src/services/api.js
import axios from 'axios';

class ApiService {
  constructor() {
    this.client = axios.create({
      baseURL: this.getBaseUrl(),
      timeout: 30000,
      headers: {
        'Content-Type': 'application/json'
      }
    });
    
    this.setupInterceptors();
  }
  
  getBaseUrl() {
    if (process.env.NODE_ENV === 'development') {
      return '/api';
    }
    return process.env.VUE_APP_API_URL || 'https://api.production.com';
  }
  
  setupInterceptors() {
    // 请求拦截器
    this.client.interceptors.request.use(config => {
      const token = localStorage.getItem('access_token');
      if (token) {
        config.headers.Authorization = `Bearer ${token}`;
      }
      return config;
    });
    
    // 响应拦截器
    this.client.interceptors.response.use(
      response => response.data,
      error => {
        if (error.response?.status === 401) {
          // token 过期处理
          this.handleUnauthorized();
        }
        return Promise.reject(error);
      }
    );
  }
  
  // 封装常用方法
  get(url, params = {}) {
    return this.client.get(url, { params });
  }
  
  post(url, data = {}) {
    return this.client.post(url, data);
  }
  
  // 更多方法...
}

export default new ApiService();

// 2. 在组件中使用
import api from '@/services/api';

export default {
  methods: {
    async loadData() {
      try {
        const users = await api.get('/users');
        const products = await api.post('/products/search', { category: 'electronics' });
        // 处理数据
      } catch (error) {
        // 统一错误处理
        console.error('请求失败:', error);
      }
    }
  }
};
相关推荐
TELL5211 天前
vue前端架构
vue
南城以南溫暖如初1472 天前
社区健身小程序开发流程详解:技术选型与实施经验分享
java·经验分享·spring boot·mysql·vue·apache
万亿少女的梦1682 天前
基于Spring Boot、Vue与MySQL的私人健身教练预约管理系统设计
java·spring boot·mysql·vue·预约管理
满栀5853 天前
vue动态路由效果
前端·javascript·vue.js·前端框架·vue
碧水澜庭4 天前
头条【vue+fastapi 】全栈教学项目系列之《02_双系统零基础环境搭建手册》
vue·fastapi
DsirNg6 天前
从 `@wheel.prevent.stop` 到事件捕获:一次讲清浏览器事件流与 Vue 事件修饰符
javascript·vue·事件修饰符·事件冒泡·dom 事件·事件捕获·wheel
其美杰布-富贵-李6 天前
Vue 3 模板语法速通:彻底理解 `:`、`@`、`#`、`v-if`、`v-for` 与 `v-model`
vue
DsirNg6 天前
基于拓扑排序的画布自动布局:用最长上游路径决定节点列级
vue·流程图·拓扑排序·状态管理·有向图·自动布局·最长路径
way_hj7 天前
Flask笔记(2)快速web项目
笔记·flask·vue·web
Sterting8 天前
初识Vue3与开发环境搭建
前端·vue