代理
- 代理配置的工作原理
- 何时会走代理?
-
-
- [开发环境(npm run serve):](#开发环境(npm run serve):)
- [生产环境(npm run build):](#生产环境(npm run build):)
-
- 完整的项目配置示例
- 实践示例
前言:在 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);
}
}
}
};