vue跨域请求详解 - 完整解决方案与实战教程

在前后端分离的开发模式下,Vue 项目通常运行在 http://localhost:8080,而后端 API 服务可能部署在 http://localhost:3000 或独立的测试域名下。当你在 Vue 组件中调用后端接口时,浏览器控制台会抛出 CORS 策略拦截错误,导致请求失败、页面数据空白,这是每个 Vue 开发者都无法绕开的经典痛点。更棘手的是,即便后端已经配置了 CORS,开发环境与生产环境的跨域表现也常常不一致,让人误以为是代码写错了。

问题现象

打开 Chrome DevTools 的 Console 面板,你通常会看到以下两类报错之一:

值得注意的是,跨域请求在 Postman 或 curl 中往往能正常返回数据,唯独在浏览器里失败,这进一步说明问题出在浏览器的同源策略上,而不是后端服务本身。

原因分析

跨域问题的根源是浏览器的同源策略(Same-Origin Policy)。所谓同源,要求协议、域名、端口三者完全一致。Vue 开发服务器默认使用 http://localhost:8080,而后端接口若使用 http://localhost:3000,端口不同即构成跨域。

浏览器对跨域请求分为两类处理:

  1. 简单请求:如 GET、POST(Content-Type 为 application/x-www-form-urlencoded、multipart/form-data 或 text/plain),浏览器直接发送请求,但会检查响应头中是否包含 Access-Control-Allow-Origin
  2. 预检请求(Preflight):如 PUT、DELETE 或 Content-Type 为 application/json 的请求,浏览器会先发送一个 OPTIONS 请求,询问服务器是否允许该跨域请求。如果 OPTIONS 请求未返回正确的 CORS 头,真正的请求根本不会发出。

很多开发者只让后端在 POST 接口上加了 CORS 头,却忽略了 OPTIONS 预检请求,导致依然跨域失败。此外,Vue CLI 或 Vite 的 proxy 代理配置错误、路径重写规则不当,也会让代理形同虚设。

解决方案(附完整代码)

实际项目中,推荐组合使用以下三种方案:开发环境用代理生产环境用 Nginx 反向代理后端配置 CORS 作为兜底。下面以 Vue 3 + Vite 和 Vue 2 + Vue CLI 为例,给出完整配置。

方案一:Vue CLI 开发服务器代理(Vue 2 / Vue 3 通用)

在项目根目录创建或修改 vue.config.js

// vue.config.js
module.exports = {
  devServer: {
    // 开发服务器端口,默认 8080
    port: 8080,
    proxy: {
      // 匹配所有以 /api 开头的请求路径
      '/api': {
        // 后端真实地址,注意不要加 /api 后缀
        target: 'http://localhost:3000',
        // 允许跨域,本质是让代理服务器代替浏览器发请求
        changeOrigin: true,
        // 是否代理 websocket,一般项目不需要
        ws: false,
        // 路径重写:把 /api/user 重写为 /user
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }
}

配置完成后,在 Vue 组件中这样调用:

// 使用 axios 发起请求
import axios from 'axios'

// 基础路径设置为 /api,实际请求会被代理到 http://localhost:3000
axios.defaults.baseURL = '/api'

axios.get('/user').then(res => {
  console.log(res.data)
})
// 实际请求地址:http://localhost:8080/api/user
// 代理后转发到:http://localhost:3000/user

方案二:Vite 开发服务器代理(Vue 3 + Vite)

在项目根目录修改 vite.config.js

// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  server: {
    port: 8080,
    proxy: {
      // 匹配 /api 开头的请求
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
        // 重写路径,去掉 /api 前缀
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
})

Vite 的 rewrite 与 Vue CLI 的 pathRewrite 写法不同,迁移项目时务必注意。

方案三:后端 CORS 配置(以 Node.js Express 为例)

如果后端可控,直接开启 CORS 是最彻底的方式。安装 cors 中间件:

// server.js
const express = require('express')
const cors = require('cors')
const app = express()

// 全局启用 CORS,允许所有来源
app.use(cors({
  origin: 'http://localhost:8080', // 生产环境建议替换为具体域名
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true // 允许携带 cookie
}))

// 手动处理 OPTIONS 预检请求,防止漏配
app.options('*', cors())

app.get('/user', (req, res) => {
  res.json({ name: '张三', age: 28 })
})

app.listen(3000, () => {
  console.log('后端服务已启动:http://localhost:3000')
})

方案四:Nginx 生产环境反向代理

生产环境通常由 Nginx 统一入口,避免跨域:

# nginx.conf
server {
  listen 80;
  server_name your-domain.com;

  # 前端静态资源
  location / {
    root /usr/share/nginx/html;
    index index.html;
    try_files $uri $uri/ /index.html;
  }

  # 后端接口反向代理
  location /api/ {
    # 后端真实地址,注意末尾斜杠
    proxy_pass http://backend-server:3000/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

排查步骤清单

遇到跨域问题时,按以下顺序逐项排查:

  1. 打开 Network 面板,确认请求是否真的发出。如果状态为 blocked,说明被浏览器拦截,未到达服务器。
  2. 检查请求的 Content-Type。如果是 application/json,会触发 OPTIONS 预检,确认后端是否处理了 OPTIONS 请求。
  3. 检查代理配置中的 target 是否写错,例如多写了 /api 或漏了端口。
  4. 检查 pathRewriterewrite 是否把路径改错,导致 404。
  5. 如果携带了 Cookie,后端 CORS 必须设置 credentials: true,且 origin 不能为 *
  6. 修改 vue.config.jsvite.config.js 后,必须重启开发服务器才会生效。
  7. 生产环境检查 Nginx 的 proxy_pass 末尾斜杠,斜杠有无会导致路径拼接结果不同。

掌握以上四种方案,你就能在开发、测试、生产各阶段从容应对 Vue 跨域问题,不再被浏览器的同源策略卡住进度。