前言

作为一名普通的程序开发者,日常开发中经常会遇到各种奇怪的问题。今天我来分享一个在 Vue3 和 Spring Boot 混合开发项目中遇到的真实跨域问题。这个问题看似简单,但实际排查过程却让我花了不少时间。本文将从问题现象、分析思路、排查步骤到最终解决方案,一步步还原整个调试过程。

问题现象

在我们团队的一个前后端分离项目中,前端使用的是 Vue3,后端是 Spring Boot。正常情况下,前端通过 axios 调用后端接口应该能成功获取数据。但在某次更新之后,发现某些接口调用失败,浏览器控制台提示如下错误:

代码语言:C#

自动换行AI代码解释


Access to fetch at 'http://api.example.com/data' from origin 'http://localhost:8081' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

起初我以为是后端配置出了问题,但查看了 Spring Boot 的相关配置,发现已经添加了 @CrossOrigin 注解,并且也设置了 spring.mvc.cors.allowed-origins。然而问题依旧存在,这就让人感到困惑了。

问题分析

首先,我回顾一下 Vue3 和 Spring Boot 的通信机制。前端通过 axios 发送请求,后端通过 Spring Boot 提供 REST 接口。跨域问题是由于浏览器的安全策略导致的,只有当后端返回的响应头中包含 Access-Control-Allow-Origin 字段时,浏览器才会允许该请求。

可能的原因包括:

  • 后端没有正确设置 CORS 配置

  • 前端请求的域名和后端配置的允许域名不一致

  • 请求方式或请求头不符合 CORS 规范

  • 使用了代理服务器,但未正确配置

排查步骤

1. 检查后端 CORS 配置

首先确认后端是否真的启用了 CORS 支持。我们在 Spring Boot 中通常有两种方式启用 CORS:

方式一:使用 @CrossOrigin 注解

代码语言:Java

自动换行AI代码解释


@RestController @RequestMapping("/api") @CrossOrigin(origins = "http://localhost:8081") public class DataController { @GetMapping("/data") public ResponseEntity<String> getData() { return ResponseEntity.ok("Hello from backend!"); } }

方式二:全局配置

代码语言:Java

自动换行AI代码解释


@Configuration @EnableWebMvc public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("http://localhost:8081") .allowedMethods("GET", "POST") .allowedHeaders("*") .exposedHeaders("Access-Control-Allow-Origin") .maxAge(3600) .allowCredentials(true); } }

但即使这样,仍然无法解决问题,说明可能还有其他问题。

2. 使用 Postman 测试接口

为了排除前端问题,我尝试使用 Postman 直接访问后端接口,结果发现接口可以正常返回数据,说明后端逻辑没问题。这说明问题出在浏览器的 CORS 策略上。

3. 检查前端请求配置

在 Vue3 中,我们使用 axios 发送请求,代码如下:

代码语言:JavaScript

代码运行次数:0

自动换行运行AI代码解释


import axios from 'axios'; const apiClient = axios.create({ baseURL: 'http://api.example.com', timeout: 5000, }); export default { async fetchData() { try { const response = await apiClient.get('/data'); console.log(response.data); } catch (error) { console.error('Error fetching data:', error); } }, };

看起来没有问题,但问题还是存在。

4. 检查浏览器控制台输出

再次打开浏览器控制台,发现除了之前的错误信息外,还有一条额外的信息:

代码语言:C#

自动换行AI代码解释


Request URL: http://api.example.com/data Request Method: GET Status Code: 200 OK Remote Address: 127.0.0.1:8080 Referrer Policy: no-referrer-when-downgrade

但是,响应头中并没有 Access-Control-Allow-Origin 字段。这说明后端虽然配置了 CORS,但实际上没有生效。

5. 检查后端日志

查看 Spring Boot 应用的日志,发现确实有请求到达,但没有看到任何关于 CORS 的日志。这说明可能是 Spring Boot 的 CORS 配置没有被正确加载。

6. 检查 Spring Boot 的依赖和版本

发现我们的项目中使用的是 Spring Boot 2.6.x,而有些 CORS 相关的类在较新的版本中发生了变化。我们尝试升级到 Spring Boot 2.7.x,问题依然存在。

7. 检查是否使用了反向代理

我们项目中使用 Nginx 作为反向代理。检查 Nginx 配置文件,发现没有设置 Access-Control-Allow-Origin 头,因此导致浏览器认为请求被拦截。

8. 修改 Nginx 配置

在 Nginx 配置中添加以下内容:

代码语言:C#

自动换行AI代码解释


location /api { proxy_pass http://localhost:8080; add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'text/plain; charset=utf-8'; add_header 'Content-Length' 0; }

保存并重启 Nginx 后,问题终于也是完美解决

总结

这次跨域问题虽然看似简单,但排查过程却非常复杂。从后端配置到前端请求,再到反向代理的设置,每一个环节都可能成为问题的根源。通过逐步排查,最终找到了问题所在——Nginx 没有正确设置 CORS 头。

对于类似的问题,建议在开发过程中尽早测试接口,避免后期出现难以定位的问题。同时,合理配置反向代理也是确保前后端分离项目顺利运行的重要一步。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐