前端和后端软件系统联调经典问题汇总

彻底理解「CORS policy: No 'Access-Control-Allow-Origin'」跨域错误

作为编程新手,在前后端联调时经常会遇到如下报错:

复制代码
Access to XMLHttpRequest at 'http://localhost:8120/login' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

本文将从问题本质、产生原因和解决方案三个层面,用通俗易懂的方式讲解这个错误。

一、理解报错信息

1. 核心概念:跨域(CORS)

浏览器遵循「同源策略」:只有当请求的协议、域名和端口完全一致时,才允许前端获取后端数据,否则就是跨域请求。

以报错为例:

2. 报错解析

报错片段 解释
Access to XMLHttpRequest at 'http://localhost:8120/login' 前端尝试请求后端接口
from origin 'http://localhost:3000' 前端源为3000端口
blocked by CORS policy 被浏览器跨域规则拦截
No 'Access-Control-Allow-Origin' header 后端响应缺少关键跨域头信息

总结:浏览器出于安全考虑阻止了跨域请求,因为后端未明确授权前端访问。

二、产生原因

浏览器设计「同源策略」是为了安全(如防止恶意网站窃取登录信息),但给开发带来不便。

跨域请求流程:

  1. 前端发送请求到后端
  2. 浏览器检查是否同源
  3. 对于复杂请求(如POST),浏览器先发送OPTIONS预检请求
  4. 若后端响应缺少Access-Control-Allow-Origin头,浏览器拦截请求

三、解决方案(按优先级)

方法1:后端配置跨域(推荐方案)

Spring Boot + Spring Security配置示例:
java 复制代码
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .cors(cors -> cors.configurationSource(corsConfigurationSource()))
            .csrf(csrf -> csrf.disable())
            .authorizeHttpRequests(auth -> auth
                .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .requestMatchers("/api/**").permitAll()
                .anyRequest().permitAll()
            )
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            )
            .formLogin(form -> form.disable());
        
        return http.build();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("http://localhost:3000");
        config.setAllowCredentials(true);
        config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        config.setAllowedHeaders(Arrays.asList("*"));
        config.setMaxAge(3600L);
        
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
    }
}

方法2:前端代理配置(临时方案)

当后端暂时无法修改时,前端可通过设置代理使请求"伪装"为同源请求。

Vue项目配置(基于Vite):
javascript 复制代码
export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:8120',
        changeOrigin: true
      }
    }
  }
});
React项目配置:
json 复制代码
{
  "proxy": "http://localhost:8120"
}

方法3:重定向问题排查

检查:

  1. 前端请求为何会跳转到不同端口?
  2. 重定向后的接口路径是否正确?

四、常见错误与解决方案

  1. 跨域配置层级问题
  • 错误:仅在Controller层使用@CrossOrigin
  • 解决方案:在SecurityConfig中配置全局跨域
  1. Cookie跨域问题
  • 错误:使用通配符*时尝试携带Cookie
  • 解决方案:指定具体前端地址
  1. 预检请求处理
  • 错误:未放行OPTIONS请求
  • 解决方案:添加requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
  1. 无状态会话配置
  • 错误:未配置无状态会话
  • 解决方案:添加.sessionCreationPolicy(SessionCreationPolicy.STATELESS)

五、验证配置是否生效

使用浏览器开发者工具:

  1. 按F12 → Network标签
  2. 触发请求 → 查看Response Headers
  3. 确认存在Access-Control-Allow-Origin: http://localhost:3000

六、总结

核心问题:浏览器因安全机制拦截跨域请求,需后端明确授权

解决方案:

  1. 后端配置跨域(Spring Security项目需特别注意)
  2. 前端代理是临时方案
  3. 重点检查:放行OPTIONS请求、配置正确前端源、开启无状态会话

注意:确保启动类扫描到SecurityConfig所在包

上面的启动类要指定扫描你的SecurityConfig类所在包"com.exam.config"

java 复制代码
- 默认扫描行为 :未显式指定 @ComponentScan 时,Spring Boot会扫描 启动类所在包及其所有子包 (即 com.exam 及其所有子包,包括 com.exam.config )。
- 显式扫描覆盖 :添加显式 @ComponentScan(basePackages=...) 后,默认扫描范围被完全覆盖,Spring仅扫描 指定的包路径 ,不会自动包含启动类所在包的子包。
- 配置失效原因 :

- 移除 "com.exam.config" 后,您自定义的 SecurityConfig.java (位于 com.exam.config 包)未被Spring容器加载
- Spring使用了默认的 WebSecurityConfiguration 和 defaultSecurityFilterChain
- 默认配置没有您自定义的CORS设置( CorsConfigurationSource ),导致跨域请求被拦截
- 默认配置启用了表单登录,将POST请求重定向至GET /login,进一步导致跨域请求失败
相关推荐
小村儿几秒前
连载10-Sub-agents 深度解析:从源码理解 Claude Code 的分身术
前端·后端·ai编程
笨拙的老猴子5 分钟前
[特殊字符] Java GC机制详解:G1、ZGC、Shenandoah全面解析与版本演进对比
java·开发语言
IT_陈寒35 分钟前
Vite动态导入把我坑惨了,原来要这样用才对
前端·人工智能·后端
砍材农夫35 分钟前
物联网 基于netty构建mqtt协议规范(遗嘱与保留消息)
java·开发语言·物联网·netty
DFT计算杂谈38 分钟前
KPROJ编译教程
java·前端·python·算法·conda
觅_41 分钟前
前端学习后端的时候 选择一个技术
前端·学习
独泪了无痕44 分钟前
CryptoJS:数据安全的JavaScript加密利器
前端·vue.js·node.js
重生之我是Java开发战士1 小时前
【笔试强训】Week5:空调遥控, kotor和气球,走迷宫,主持人调度II,体操队形,二叉树的最大路径和,排序子序列,消减整数
java·算法·动态规划
发现一只大呆瓜1 小时前
一文搞懂 Vite 处理CommonJS包、按需编译逻辑及 Rollup 插件兼容规则
前端
Edwardwu1 小时前
写了个y-mxgraph:给 draw.io 接上了 Yjs,顺便解决了部署在 iframe 里的一堆问题
前端·typescript