前端开发中的跨域问题:Vite 开发环境配置指南

前言

在前端开发过程中,跨域问题是一个经常遇到的挑战。当你的前端应用运行在 http://localhost:5173,而后端 API 运行在 http://2.x.x.x:28xxx 时,浏览器会阻止这种跨域请求。本文将详细介绍如何使用 Vite 的代理功能来解决开发环境中的跨域问题。

什么是跨域?

跨域(Cross-Origin Resource Sharing,CORS)是浏览器的同源策略限制。当以下三个要素中任意一个不同时,就会产生跨域:

  • 协议(Protocol):如 httphttps
  • 域名(Domain):如 localhost2.x.x.x
  • 端口(Port):如 517328xxx

当浏览器检测到跨域请求时,会抛出类似以下的错误:

Access to XMLHttpRequest at 'http://2.x.x.x:28xxx/login' from origin 'http://localhost:5173' 
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

解决方案对比

1. 后端配置 CORS(生产环境推荐)

在后端服务器设置响应头,允许指定的源访问:

// 后端示例(Node.js/Express)
app.use(cors({
  origin: 'http://localhost:5173',
  credentials: true
}));

优点:符合生产环境最佳实践
缺点:需要后端配合,开发环境可能无法修改后端

2. 浏览器插件(不推荐)

使用 Chrome 插件禁用 CORS 检查。

优点:快速
缺点:仅适用于开发,不安全,不推荐

3. Vite 代理(开发环境推荐)⭐

利用 Vite 开发服务器的代理功能,将请求转发到后端服务器。

优点

  • 无需修改后端代码
  • 开发环境专用,不影响生产环境
  • 配置简单,功能强大
  • 可以处理路径重写、请求头修改等

Vite 代理配置详解

基础配置

vite.config.ts 中配置 server.proxy

import { defineConfig } from 'vite'

export default defineConfig({
  server: {
    // 端口号
    port: 5173,
    // 允许外部访问(局域网访问)
    host: "0.0.0.0",
    // 代理配置
    proxy: {
      // 代理所有以 /api 开头的请求
      "/api": {
        // 目标服务器地址
        target: "http://后端地址",
        // 改变请求头中的 origin,确保后端能正确识别来源
        changeOrigin: true,
        // 路径重写:去掉 /api 前缀
        rewrite: (path) => path.replace(/^/api/, "")
      }
    }
  }
})

配置项说明

target
  • 类型string
  • 说明:后端服务器的实际地址
  • 示例"http://后端地址"
changeOrigin
  • 类型boolean
  • 默认值false
  • 说明:是否改变请求头中的 origin 字段
  • 作用:当设置为 true 时,请求头中的 origin 会被设置为 target 的值,这样可以避免后端因 origin 不匹配而拒绝请求
  • 注意:此时更改http中的baseURL为'/api'
rewrite
  • 类型(path: string) => string
  • 说明:路径重写函数
  • 作用:可以修改请求路径,例如去掉前缀、添加前缀等

示例

rewrite: (path) => path.replace(/^/api/, "")
// 请求 /api/login → 实际请求 http://后端地址/login

完整配置示例

// vite.config.ts
import { defineConfig, loadEnv } from 'vite'

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd())
  
  return {
    server: {
      port: Number(env.VITE_PORT) || 5173,
      host: "0.0.0.0",
      proxy: {
        "/api": {
          target: env.VITE_API_BASE_URL || "后端地址",
          changeOrigin: true,
          rewrite: (path) => path.replace(/^/api/, ""),
          // 可选:配置 WebSocket 代理
          ws: true,
          // 可选:自定义请求头
          configure: (proxy, options) => {
            proxy.on('proxyReq', (proxyReq, req, res) => {
              // 可以在这里修改请求头
              console.log('代理请求:', req.url)
            })
          }
        }
      },
      // CORS 配置(可选,通常不需要)
      cors: {
        origin: "*",
        credentials: true
      }
    }
  }
})

前端 HTTP 客户端配置

配置好代理后,需要在前端 HTTP 客户端中设置正确的 baseURL

Axios 配置示例

// src/utils/http/index.ts
import Axios, { type AxiosRequestConfig } from 'axios'

const defaultConfig: AxiosRequestConfig = {
  timeout: 20000,
  // 使用相对路径,Vite 会自动代理到后端
  baseURL: "/api",
  headers: {
    Accept: "application/json, text/plain, */*",
    "Content-Type": "application/json",
    "X-Requested-With": "XMLHttpRequest"
  }
}

const axiosInstance = Axios.create(defaultConfig)

// 使用示例
export const http = {
  get: <T>(url: string, config?: AxiosRequestConfig) => {
    return axiosInstance.get<T>(url, config)
  },
  post: <T>(url: string, data?: any, config?: AxiosRequestConfig) => {
    return axiosInstance.post<T>(url, data, config)
  }
}

请求流程

  1. 前端发起请求

    http.post("/login", { username: "admin", password: "123456" })
    
  2. 实际请求路径

    http://localhost:5173/api/login
    
  3. Vite 代理转发

    http://后端地址/login  (去掉了 /api 前缀)
    
  4. 后端响应

    响应原路返回 → Vite 代理 → 前端
    

高级配置场景

1. 多个代理规则

当需要代理多个不同的后端服务时:

proxy: {
  "/api": {
    target: "http://api.example.com",
    changeOrigin: true,
    rewrite: (path) => path.replace(/^/api/, "")
  },
  "/upload": {
    target: "http://upload.example.com",
    changeOrigin: true
  }
}

2. 使用正则表达式匹配

proxy: {
  // 匹配所有以 /api 或 /v1 开头的请求
  "^/api|^/v1": {
    target: "http://2.2.50.2:28082",
    changeOrigin: true
  }
}

3. 代理 WebSocket

proxy: {
  "/api": {
    target: "ws://后端地址",
    ws: true,  // 启用 WebSocket 代理
    changeOrigin: true
  }
}

4. 自定义请求头

proxy: {
  "/api": {
    target: "http://后端地址",
    changeOrigin: true,
    configure: (proxy, options) => {
      proxy.on('proxyReq', (proxyReq, req, res) => {
        // 添加自定义请求头
        proxyReq.setHeader('X-Custom-Header', 'custom-value')
      })
    }
  }
}

常见问题排查

1. 代理不生效

检查项

  • 确认 vite.config.ts 配置正确
  • 重启 Vite 开发服务器
  • 检查 baseURL 是否以 /api 开头
  • 查看浏览器 Network 面板,确认请求是否发送到正确的地址

2. 请求 404

可能原因

  • rewrite 配置不正确,路径被错误重写
  • target 地址不正确
  • 后端路由不存在

解决方案

// 添加日志查看实际请求路径
configure: (proxy, options) => {
  proxy.on('proxyReq', (proxyReq, req, res) => {
    console.log('代理请求路径:', proxyReq.path)
  })
}

3. Cookie 丢失

原因:跨域请求默认不携带 Cookie

解决方案

proxy: {
  "/api": {
    target: "http://2.2.50.2:28082",
    changeOrigin: true,
    // 确保 Cookie 被正确传递
    cookieDomainRewrite: "",
    cookiePathRewrite: ""
  }
}

4. 生产环境配置

重要:Vite 的代理功能仅在开发环境生效,生产环境需要:

  1. 使用 Nginx 反向代理

    location /api {
        proxy_pass http://2.2.50.2:28082;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    
  2. 或后端配置 CORS

    // 允许所有源(生产环境建议指定具体域名)
    app.use(cors({
      origin: process.env.ALLOWED_ORIGINS?.split(',') || '*',
      credentials: true
    }))
    

最佳实践

1. 使用环境变量

// .env.development
VITE_API_BASE_URL=http://后端地址
VITE_PORT=5173

// vite.config.ts
export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd())
  
  return {
    server: {
      proxy: {
        "/api": {
          target: env.VITE_API_BASE_URL,
          changeOrigin: true,
          rewrite: (path) => path.replace(/^/api/, "")
        }
      }
    }
  }
})

2. 类型安全

// 定义 API 响应类型
export interface ApiResponse<T> {
  code: number
  msg: string
  data: T
}

// 使用示例
const response = await http.post<ApiResponse<UserInfo>>("/login", {
  username: "admin",
  password: "123456"
})

3. 错误处理

axiosInstance.interceptors.response.use(
  (response) => response.data,
  (error) => {
    if (error.response) {
      // 服务器返回错误
      console.error('服务器错误:', error.response.status)
    } else if (error.request) {
      // 请求已发送但没有收到响应
      console.error('网络错误:', error.request)
    } else {
      // 请求配置错误
      console.error('请求错误:', error.message)
    }
    return Promise.reject(error)
  }
)

总结

Vite 的代理功能是解决开发环境跨域问题的最佳方案:

无需修改后端代码
配置简单,功能强大
仅影响开发环境,不影响生产环境
支持路径重写、请求头修改等高级功能

通过合理配置 Vite 代理,可以大大提升前端开发效率,避免跨域问题带来的困扰。

参考文档

  • Vite 官方文档 - 服务器选项-proxy
  • MDN - CORS
  • Axios 官方文档

希望这篇文章能帮助你解决跨域问题!如果还有疑问,欢迎在评论区讨论。

本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]