Code前端首页关于Code前端联系我们

Vue3本地开发调接口总报CORS跨域?3种亲测有用的解决方法+避坑指南

terry 1小时前 阅读数 17 #Vue

最近好几个刚转Vue3开发的朋友私信问我,说本地起Vue3项目连公司或者测试服接口,要么弹Network Error,要么控制台红一片写“Access-Control-Allow-Origin missing”,明明后台同事说接口没问题,代码写得跟以前Vue2差不多,这到底咋回事?其实Vue3本地开发的跨域核心逻辑和Vue2没变,但Vite(大多数Vue3项目现在用的构建工具)和Webpack的代理配置语法不一样,再加上不少人忽略了一些生产环境和测试环境的切换细节,才容易踩坑,今天就把我踩过的坑和整理的实用方案给大家唠明白。

先搞懂:为啥本地开发Vue3会报CORS跨域?

不是只有Vue3会报,只要是前端服务后端接口不在同一个“源”上,浏览器的同源策略就会把请求拦截掉,那啥是“同一个源”呢?简单说就是协议(http/https)、域名(比如localhost、test.xxx.com)、端口(比如8080、3000)三者必须完全一致——差一个都不行。

举个例子你就懂了:你本地用Vite起的Vue3项目可能跑在http://localhost:5173(Vite默认端口现在是5173,Webpack是8080/8081),但测试服的接口地址是https://test.xxx.com/api/getUserInfo,这时候协议(http vs https)、域名(localhost vs test.xxx.com)、端口(5173 vs 默认https的443)全不一样,浏览器肯定不让你发请求,后台就算开了CORS也没用?不对,后台开了CORS其实也能连,但很多公司测试服为了安全不会随便开所有域名的白名单,只开线上前端的,所以本地开发还是得用其他办法。

Vite/Webpack本地代理(最推荐,零后台配合)

不管用Vite还是Webpack,本地构建工具都自带反向代理功能——简单说就是让浏览器把请求发给本地的构建工具服务(因为和前端源一致,不会跨域),然后构建工具偷偷把请求转发给真正的后台接口,回来的数据再原路返回给前端,相当于中间搭了个“跳板”,完美绕过同源策略,这个方案不需要后台改任何东西,自己改改配置就行,是我日常开发用得最多的。

如果你的Vue3用的是Vite(90%以上的新项目)

  1. 打开项目根目录下的vite.config.js(如果用TS就是vite.config.ts),找到export default defineConfig里的server配置项,没有的话自己加上。
  2. server里加一个proxy对象,举个配置例子:
    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'

export default defineConfig({ plugins: [vue()], server: { port: 5173, // 可以改成你习惯的端口 open: true, // 自动打开浏览器 proxy: { // 这里的/api是“拦截规则”——只要前端请求的地址开头是/api,就会被转发 '/api': { target: 'https://test.xxx.com', // 真正的后台接口地址(注意不要加/api后缀!除非后台接口本身就有统一的api前缀但不用转发) changeOrigin: true, // 这个必须开!作用是把请求头里的Origin改成target的域名,防止后台做Origin校验的时候拦截 rewrite: (path) => path.replace(/^\/api/, '') // 这个看情况:如果后台接口本身没有统一的/api前缀(比如真正的接口是/getUserInfo),但前端为了区分静态资源和接口,统一加了/api前缀,就需要这行代码把/api去掉;如果后台接口本身有统一的/api前缀(比如真正的接口是/api/getUserInfo),就把这行注释掉或者删掉 } } } })

改完配置**一定要重启Vite服务**!很多新手改完直接刷新页面,发现还是报错,就是忘了这一步。
4. 前端请求的地址怎么写?比如刚才的例子,真正的接口是`https://test.xxx.com/getUserInfo`(需要rewrite去掉/api),那前端直接写`/api/getUserInfo`就行,Vite会自动帮你转发;如果真正的接口是`https://test.xxx.com/api/getUserInfo`(不需要rewrite),前端也直接写`/api/getUserInfo`,转发过去就是完整的了。
#### 如果你的Vue3用的是Webpack(比如旧项目迁移过来的)
Webpack的代理配置和Vite逻辑一样,但语法略有不同,配置文件是根目录下的`vue.config.js`,同样举个例子:
```javascript
module.exports = {
  devServer: {
    port: 8080,
    open: true,
    proxy: {
      '/api': {
        target: 'https://test.xxx.com',
        changeOrigin: true,
        pathRewrite: { // Webpack这里叫pathRewrite,Vite叫rewrite,都是替换路径的意思
          '^/api': ''
        }
      }
    }
  }
}

同样,改完重启Webpack服务!

Vite/Webpack代理避坑指南

  1. 拦截规则不能随便写,也不能漏写斜杠前缀:比如别写成api,要写成/api,不然静态资源如果名字里有api也会被转发,比如你的图片叫api-logo.png,就会变成请求后台的api-logo.png,肯定404。
  2. changeOrigin一定要设为true:刚才说了,不然后台如果有Origin白名单,就算本地代理转发了,后台也会拒绝。
  3. rewrite/pathRewrite要按需配置:很多人搞不清什么时候加什么时候不加,这里教你个小技巧:把前端请求的地址,用浏览器直接访问,看看能不能拿到后台的数据(如果后台开了CORS的话),或者用Postman测测——比如前端写的是/api/getUserInfo,你复制到Postman里改成https://test.xxx.com/api/getUserInfo测通了,就不需要rewrite;如果改成https://test.xxx.com/getUserInfo才测通,就需要rewrite去掉开头的/api
  4. 代理只在开发环境生效,生产环境没用:这个非常重要!很多人开发环境用代理跑通了,直接打包上线,结果发现接口404,就是忘了生产环境要处理跨域——生产环境要么让后台开CORS白名单,要么用Nginx反向代理(后面会讲)。

让后台开CORS白名单(适合长期维护的内部项目)

如果你的项目是内部使用的,或者后台同事愿意配合,开CORS白名单是最彻底的方案——不管是本地开发还是线上,都能用,不用改前端配置,但要注意,*千万不要让后台开`Access-Control-Allow-Origin: `(允许所有域名访问)**,除非是完全公开的接口,不然会有很大的安全隐患,比如CSRF攻击。

后台开CORS的方式因后端语言而异,比如Java(Spring Boot)加个@CrossOrigin注解或者配置拦截器,Node.js(Express/Koa)用cors中间件,Python(Django/Flask)用相应的CORS插件,具体怎么写可以让后台同事查一下官方文档,都是很简单的配置。

如果后台开了白名单,前端请求直接写完整的接口地址就行,比如https://test.xxx.com/api/getUserInfo,不需要加任何前缀,也不需要代理。

后台开CORS避坑指南

  1. 如果请求是带Cookie的,需要额外配置:比如前端用axios发请求的时候要设withCredentials: true,后台也要设Access-Control-Allow-Credentials: true,而且Access-Control-Allow-Origin不能设为,必须设为具体的域名(比如本地开发的http://localhost:5173,线上的https://www.xxx.com)。
  2. 如果请求是非简单请求,需要处理预检请求(OPTIONS):啥是非简单请求?比如请求方法是PUT/DELETE,或者请求头里有自定义的字段(比如tokenuser-id),浏览器会先发送一个OPTIONS预检请求,问后台“这个非简单请求能不能发”,后台必须返回200状态码,并且把允许的请求方法、请求头都列出来,浏览器才会发送真正的请求,很多新手前端带自定义token发请求报错,就是后台没处理OPTIONS预检请求。

Nginx反向代理(适合生产环境,或者后台不开CORS的内部测试)

生产环境一般不会用Vite/Webpack的代理,都是用Nginx做反向代理——原理和本地构建工具的代理一样,就是让Nginx同时监听前端静态资源和后台接口的请求,浏览器把所有请求都发给Nginx(协议、域名、端口都一致,不会跨域),Nginx根据请求路径把静态资源返回给浏览器,把接口请求转发给后台。

比如你的Nginx监听https://www.xxx.com(端口443),前端静态资源放在/usr/local/nginx/html/vue3-project目录下,后台接口地址是https://api.xxx.com,那Nginx的配置大概是这样的:

server {
    listen 443 ssl;
    server_name www.xxx.com;
    # SSL证书配置(这个你自己填)
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    # 前端静态资源的配置
    location / {
        root /usr/local/nginx/html/vue3-project;
        index index.html index.htm;
        try_files $uri $uri/ /index.html; # 这个很重要!Vue3是单页应用(SPA),路由是前端控制的,如果刷新页面Nginx找不到对应的文件,就会返回404,加了这行就会把所有非静态资源的请求都返回给index.html,让前端路由去处理
    }
    # 后台接口的代理配置
    location /api {
        proxy_pass https://api.xxx.com; # 注意这里如果后台接口本身有/api前缀,proxy_pass后面要加吗?和本地代理一样,按需配置:比如前端请求的是/api/getUserInfo,后台真正的接口是/api/getUserInfo,就直接写https://api.xxx.com;如果后台真正的接口是/getUserInfo,就写https://api.xxx.com/(注意最后有个斜杠,会把/api去掉)
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme; # 如果是HTTPS转HTTP或者反过来,这个必须开
    }
}

改完Nginx配置记得重启Nginx服务!

Nginx反向代理避坑指南

  1. try_files一定要加:刚才说了,SPA刷新页面404的问题99%都是因为没加这行。
  2. proxy_pass后面的斜杠很重要:比如location /apiproxy_pass https://api.xxx.com,会把前端的/api/getUserInfo转发成https://api.xxx.com/api/getUserInfo;如果proxy_pass https://api.xxx.com/,会把/api/getUserInfo转发成https://api.xxx.com/getUserInfo,这个细节一定要注意,不然容易404。
  3. 如果是内部测试,没有域名,可以用Nginx监听本地IP+端口:比如监听http://192.168.1.100:8080,其他同事可以用这个IP访问你的前端项目,也能连后台接口(前提是其他同事和你在同一个局域网,后台接口允许局域网IP访问)。

总结一下这3种方案的适用场景

  1. 本地开发阶段:首选Vite/Webpack本地代理,零后台配合,方便快捷。
  2. 长期维护的内部项目:可以让后台开CORS白名单,本地和线上都能用。
  3. 生产环境:首选Nginx反向代理,安全稳定,还能处理SPA刷新404的问题;如果是完全公开的接口,也可以让后台开CORS白名单。

最后再提醒大家一句,遇到跨域问题不要慌,先看控制台的报错信息,确定是同源策略拦截的,还是后台接口本身的问题,然后再根据场景选择合适的方案,如果还有其他Vue3跨域的问题,欢迎在评论区留言讨论!

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门