【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);
      }
    }
  }
};
相关推荐
那年那棵树4 天前
基于WebGis的人生如旅地图系统
前端·arcgis·vue·课程设计
冒险的豆子7 天前
Vue2 、Vue3 响应式对比及优劣
vue
NetX行者8 天前
用 Vite + Vue3 + UnoCSS 搭建企业级项目模板(一):基础骨架
vue·vite·unocss
java水泥工8 天前
什么是前端
java·vue·html5
mont evergreen9 天前
一封从外部世界寄来的信:二维码数据如何穿越三重门,抵达你的屏幕
electron·vue·事件
志尊宝10 天前
Vue3 零基础每日笔记(071):暗黑模式与主题切换——CSS 变量 + Element Plus 暗黑方案
前端·css·笔记·vue·html·前端开发·软件开发
怦然丶心动10 天前
用 Java 把干支历法算清楚:从节气切年到可读摘要
java·算法·vue·独立开发·spring boot / spring
OnlineProxy12 天前
如何生成无限电子邮件:实现无封锁、无验证码的可扩展邮局注册架构
人工智能·proxy模式
我最爱吃鱼香茄子12 天前
【毕业设计优选】人力资源管理系统|Java|SpringBoot|Vue|前后端分离|带详细文档+部署教学视频
java·vue·毕业设计·springboot
骑着蜗牛撵大象32713 天前
SpringBoot+Vue3 企业智能体侧挂架构:独立服务、独立数据库与主线零侵入落地
数据库·spring boot·架构·vue·springboot·事件驱动·服务拆分