当前位置: 首页 > news >正文

【浏览器CORS问题解决方案】SpringBoot+Vue3前后端全覆盖:浏览器跨域问题的多样化解决方案

简言:

本文聚焦前后端分离开发中常见的浏览器跨域问题,以 SpringBoot 后端和 Vue3 前端为核心场景,系统梳理了 5 种解决方案:后端涵盖单个接口 @CrossOrigin 注解、全局配置类(推荐)、过滤器 Filter 配置 3 种核心方案,前端包含 Vite 代理配置(开发环境专用)、Axios 请求拦截器(配合后端,生产环境可用)2 种实用方案。每种方案均搭配详细实操步骤、可直接复用的代码及清晰流程图,同时提供场景选型指南与常见问题排查技巧,助力读者快速理解跨域原理并根据实际需求落地解决方案。

文章目录

    • 一、先搞懂:什么是跨域?为什么会被拦截?
    • 二、后端SpringBoot解决跨域:3种核心方案
      • 方案1:最简洁——单个接口加@CrossOrigin注解
      • 方案2:最常用——全局配置类(推荐)
      • 方案3:最灵活——过滤器Filter配置
    • 三、前端Vue3解决跨域:2种实用方案
      • 方案1:开发环境专用——Vite代理配置(最常用)
      • 方案2:生产环境可用——Axios请求拦截器(配合后端)
    • 四、总结:不同场景怎么选方案?
    • 五、常见问题排查

一、先搞懂:什么是跨域?为什么会被拦截?

简单说,当浏览器的请求地址(比如前端Vue项目的http://localhost:5173)和服务器接口地址(比如后端SpringBoot项目的http://localhost:8080)满足“协议、域名、端口”三者中任意一个不同时,就属于跨域请求。

那为什么浏览器要拦截呢?这是浏览器的“同源策略”在起保护作用,防止恶意网站窃取其他网站的敏感数据。但在合法的前后端分离开发中,我们就需要主动“破解”这个限制,这就是所谓的“跨域解决方案”。

小技巧:判断是否跨域的简单方法——看浏览器地址栏的地址和接口请求地址的“协议://域名:端口”是不是完全一样,不一样就是跨域。

先搭个测试环境,后面所有方案都基于这个环境验证:

  • 前端Vue3项目:运行地址 http://localhost:5173(Vite默认端口)
  • 后端SpringBoot项目:运行地址 http://localhost:8080(默认端口)
  • 测试接口:后端写一个简单的接口 /api/hello,返回“Hello 跨域测试”

未解决跨域时,前端调用接口会出现如下错误(F12打开控制台查看):

二、后端SpringBoot解决跨域:3种核心方案

后端解决跨域是最推荐的方式,因为只需要配置一次,所有前端请求都能生效,不用前端做额外处理。

方案1:最简洁——单个接口加@CrossOrigin注解

适用场景:需要跨域的接口比较少,比如只开放一两个接口给前端。

操作步骤:直接在后端的Controller接口方法上添加@CrossOrigin注解即可。


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.CrossOrigin;@RestController
@RequestMapping("/api")
public class HelloController {// 加上这个注解,允许来自http://localhost:5173的跨域请求@CrossOrigin(origins = "http://localhost:5173")@GetMapping("/hello")public String hello() {return "Hello 跨域测试";}
}

参数说明:origins指定允许跨域的前端地址,多个地址可以用逗号分隔,比如@CrossOrigin(origins = {“http://localhost:5173”, "http://www.test.com"});如果想允许所有地址跨域,可以写@CrossOrigin;如果想允许所有地址跨域,可以写@CrossOrigin)(origins = “*”)(生产环境不推荐,有安全风险)。

测试效果:前端调用接口,控制台无错误,能正常拿到返回值。

方案2:最常用——全局配置类(推荐)

适用场景:整个项目的所有接口都需要跨域,比如前后端分离的正式项目。

操作步骤:新建一个配置类,实现WebMvcConfigurer接口,重写addCorsMappings方法。


import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration // 标识这是一个配置类
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**") // 对所有接口生效.allowedOrigins("http://localhost:5173") // 允许的前端地址.allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的请求方法.allowedHeaders("*") // 允许的请求头.allowCredentials(true) // 是否允许携带Cookie(重要,前端传参如果需要Cookie必须设为true).maxAge(3600); // 预检请求的有效期,单位秒(3600表示1小时内不用重复发预检请求)}
}

关键说明:

  • addMapping("/“):表示对项目中所有接口都启用跨域配置,也可以指定特定路径,比如”/api/"只对/api开头的接口生效。
  • allowCredentials(true):如果前端需要传递Cookie(比如登录后的身份验证),这个参数必须设为true,同时allowedOrigins不能写"*",必须指定具体的前端地址。
  • maxAge(3600):浏览器发送跨域请求前,会先发送一个OPTIONS预检请求,验证是否允许跨域,这个参数设置预检请求的有效期,有效期内不用重复发送,提高性能。

方案3:最灵活——过滤器Filter配置

适用场景:需要更精细的跨域控制,比如根据不同的路径设置不同的跨域规则。

操作步骤:新建一个过滤器类,实现Filter接口,在doFilter方法中设置跨域响应头。


import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebFilter(filterName = "corsFilter", urlPatterns = "/*") // 拦截所有请求
public class CorsFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletResponse res = (HttpServletResponse) response;// 允许的前端地址res.setHeader("Access-Control-Allow-Origin", "http://localhost:5173");// 允许的请求方法res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");// 允许的请求头res.setHeader("Access-Control-Allow-Headers", "*");// 允许携带Cookieres.setHeader("Access-Control-Allow-Credentials", "true");// 预检请求有效期res.setHeader("Access-Control-Max-Age", "3600");// 如果是预检请求,直接返回200if ("OPTIONS".equals(((HttpServletRequest) request).getMethod())) {res.setStatus(HttpServletResponse.SC_OK);return;}// 继续执行后续过滤器chain.doFilter(request, response);}
}

然后在SpringBoot的启动类上添加@ServletComponentScan注解,扫描过滤器:


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;@SpringBootApplication
@ServletComponentScan // 扫描Servlet相关组件(包括过滤器)
public class CorsDemoApplication {public static void main(String[] args) {SpringApplication.run(CorsDemoApplication.class, args);}
}

三、前端Vue3解决跨域:2种实用方案

前端解决跨域的核心思路是“代理”,即通过前端项目本身作为中间代理,把请求转发给后端,因为代理服务器和前端是“同源”的,就不会触发跨域限制。

方案1:开发环境专用——Vite代理配置(最常用)

适用场景:Vue3项目用Vite构建的开发环境(生产环境建议用后端配置或Nginx代理)。

操作步骤:修改前端项目根目录下的vite.config.js文件,添加server.proxy配置。


import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'// https://vitejs.dev/config/
export default defineConfig({plugins: [vue()],server: {proxy: {// 1. 配置代理规则:以/api开头的请求都转发到目标地址'/api': {target: 'http://localhost:8080', // 后端接口的真实地址changeOrigin: true, // 开启代理,会把请求头中的Origin改成目标地址rewrite: (path) => path.replace(/^\/api/, '') // 重写路径(可选,根据接口实际路径调整)}}}
})

举个例子理解rewrite:如果后端接口实际是http://localhost:8080/hello,而前端想写/api/hello来调用,就需要rewrite把/api去掉,这样转发后就是正确的地址;如果后端接口本身就带/api前缀(比如http://localhost:8080/api/hello),就不需要rewrite。

前端调用接口示例(用Axios,需先安装:npm install axios):


// 在src/utils/request.js中配置Axios
import axios from 'axios'const request = axios.create({baseURL: '', // 因为配置了代理,这里可以空着或写 '/'timeout: 5000
})export default request// 在组件中调用
import request from '@/utils/request'async getHello() {try {const res = await request.get('/api/hello') // 这里的/api会被代理转发到后端console.log(res.data) // 输出"Hello 跨域测试"} catch (err) {console.error(err)}
}

测试效果:前端调用接口时,浏览器控制台的请求地址显示http://localhost:5173/api/hello(前端地址),但实际已经转发到http://localhost:8080/hello,不会出现跨域错误。

方案2:生产环境可用——Axios请求拦截器(配合后端)

适用场景:需要在请求头中添加特殊信息(比如Token),同时解决跨域,本质还是需要后端配合允许对应的请求头。

操作步骤:在Axios的请求拦截器中添加跨域相关的请求头,后端需要允许这些头(对应后端方案2中的allowedHeaders=“*”)。


import axios from 'axios'const request = axios.create({baseURL: 'http://localhost:8080', // 直接写后端真实地址timeout: 5000
})// 请求拦截器
request.interceptors.request.use((config) => {// 添加跨域相关的请求头(后端需允许这些头)config.headers['Access-Control-Allow-Origin'] = 'http://localhost:5173'// 可以顺便添加Token等其他头信息// config.headers['Token'] = localStorage.getItem('token')return config},(error) => {return Promise.reject(error)}
)export default request// 组件中调用
async getHello() {try {const res = await request.get('/api/hello')console.log(res.data)} catch (err) {console.error(err)}
}

注意:这种方式单独用不能解决跨域,必须配合后端的跨域配置(比如后端用方案2的全局配置),因为请求头的允许需要后端来设置。

四、总结:不同场景怎么选方案?

场景推荐方案优点
单个/少数接口跨域SpringBoot @CrossOrigin注解简单快捷,不用额外配置类
整个项目接口跨域(开发+生产)SpringBoot全局配置类一次配置全局生效,灵活可控
Vue3开发环境跨域(Vite构建)Vite代理配置不依赖后端,开发调试方便
生产环境跨域(大型项目)后端全局配置 + Nginx代理性能好,安全可靠(Nginx代理后续可单独讲)

五、常见问题排查

  • 问题1:配置后还是跨域?——检查后端allowedOrigins是否写对前端地址,前端代理的target是否写对后端地址;如果带Cookie,后端allowCredentials是否为true,且allowedOrigins不能是"*"。
  • 问题2:预检请求报错?——后端是否允许OPTIONS方法(方案2和3都已包含,方案1需要注意)。
  • 问题3:前端能请求但拿不到数据?——检查接口路径是否正确,比如代理的rewrite是否配置正确,后端接口是否返回了正确的数据。

按照上面的方案操作,基本能解决99%的SpringBoot+Vue3跨域问题。如果还有特殊场景,可以留言讨论~

http://www.dtcms.com/a/572672.html

相关文章:

  • 论述AI和人类的分工
  • 第四阶段C#通讯开发-6:Socket之UDP
  • 广州建设网站公司简介百度seo排名推广
  • 四自由度机械臂运动学与动力学分析
  • Spring Security 使用
  • Web3开发中的前端、后端与合约:角色定位与协作逻辑
  • 神经网络—— 人工神经网络
  • GroupNet:基于多尺度神经网络的交互推理轨迹预测
  • CANN 自定义算子实战:从智能门禁到工业质检,MindStudio 7.0 落地优化(时延 130ms + 漏检率 3%,代码可复现)
  • RecyclerView Item 点击 长按事件最佳实践(为什么长按要 return true?
  • 哪些软件可以做网站门户网站搭建方案
  • 【Java 开发日记】设计模式了解吗,知道什么是饿汉式和懒汉式吗?
  • HTTPDNS 并非是 DoH/DoT 中的一种
  • spring boot 请求分发器
  • 百度站长收录入口如何判断网站好坏
  • RVO和移动语义
  • 阻塞队列 BlockingQueue 全解析:从 ArrayBlockingQueue 到 LinkedBlockingQueue
  • Autoware.universe多点导航和避障绕障设置
  • 计网6.1 网络应用模型
  • YOLO系列算法学习:YOLOv8:系列又一力作
  • 自动化测试-YAML
  • UnityGLTF 材质创建与赋值流程
  • 专业英文网站建设外贸业务怎么利用网站开发客户
  • 泰州网站建设策划做棋牌网站合法
  • uniapp开发ai对话app,使用百度语音识别用户输入内容并展示到页面上
  • 【XR技术介绍】Inside-Out Tracking:为何成为主流?核心技术:视觉SLAM原理通俗解读
  • Vue3 项目 GitLab CI/CD 自动构建并推送到 Harbor 教程
  • 【XR硬件系列】夸克 AI 眼镜预售背后:阿里用 “硬件尖刀 + 生态护城河“ 重构智能穿戴逻辑
  • 怎么查网站关键词排名个人网站设计企业
  • 金融机构如何用企业微信实现客户服务优化?