Spring Boot 全局跨域配置与前后端联调避坑

7 阅读11分钟

Spring Boot 全局跨域配置与前后端联调避坑

在前后端分离开发模式中,跨域问题是联调阶段最常见、最容易卡进度的问题之一。前面我们完成了接口开发、全局异常处理、参数校验、接口日志统一打印等基础能力搭建,项目接口已经具备完整的业务能力和问题排查能力。但一旦前端通过Vue、React等框架独立部署访问后端接口,浏览器就会触发CORS跨域拦截,出现控制台报跨域错误、请求无响应、预检请求失败、403跨域拒绝等问题,导致前后端完全无法联调。

很多新手解决跨域只会简单使用注解或者配置通配符,看似临时解决问题,却会埋下大量线上隐患:生产环境跨域失效、携带Token请求报错、PUT/DELETE请求拦截、SpringSecurity冲突、多配置优先级混乱等。本文将从跨域核心原理入手,讲解企业级标准的全局跨域配置方案,对比多种配置方式的优劣,重点梳理前后端联调的高频坑点与解决方案,适配Spring Boot2.x、3.x全版本,一套配置适配开发、测试、生产全环境,彻底根治跨域问题。

一、跨域核心原理与产生原因

1.1 什么是跨域

跨域全称跨域资源共享(CORS),是浏览器为了防范恶意网站窃取数据的安全同源策略限制。浏览器规定:只有协议、域名、端口三者完全一致,才属于同源请求,允许正常访问接口;任意一个要素不同,即判定为跨域请求,浏览器会拦截响应数据。

前后端分离项目天然存在跨域场景:前端本地运行在 http://localhost:8080,后端接口运行在 http://localhost:8088,端口不一致,直接触发跨域拦截。需要注意的是:跨域是浏览器的限制,和后端服务无关,后端接口本身已经正常执行,只是浏览器拒绝接收响应结果。

1.2 简单请求与预检请求(核心避坑基础)

浏览器将跨域请求分为两类,不同请求的跨域校验规则完全不同,绝大多数联调报错都源于对这两种请求的认知缺失:

1. 简单请求

仅支持 GET、POST、HEAD 三种请求方式,且请求头仅包含基础字段、无自定义请求头、无复杂请求体。简单请求不会发送预检请求,浏览器直接发起接口请求,通过响应头判断是否允许跨域。

2. 预检请求(OPTIONS请求)

PUT、DELETE 请求、携带 Token 自定义请求头、复杂JSON请求体等场景,都会触发预检请求。浏览器会先发送一次 OPTIONS 预检请求,询问后端是否允许当前跨域请求,预检通过后,才会发起真正的业务请求。若后端未处理 OPTIONS 请求,会直接跨域报错,业务请求无法执行。

同时 Spring Boot 3.x 对预检请求规则大幅收紧,旧版本默认兼容所有请求方法,3.x 版本默认仅允许 GET、POST、HEAD,若未手动配置 PUT、DELETE 方法,会直接拦截请求,这是高版本项目跨域失效的核心原因之一。

二、常见跨域解决方案优劣对比

Spring Boot 提供多种跨域解决方案,不同方案适配场景、优先级、稳定性差异极大,新手极易混用导致冲突。这里对四种主流方案做完整对比,帮助大家按需选择:

2.1 @CrossOrigin 注解(局部方案,不推荐全局使用)

直接在 Controller 类或接口方法上添加注解,仅对当前类/接口生效,优点是使用简单、按需开启,缺点是配置分散、无法统一管理、后期维护成本极高,大型项目不推荐使用。同时该注解和全局配置混用会出现优先级混乱,导致跨域规则失效。

2.2 过滤器跨域配置(CorsFilter)

通过注册 CorsFilter 过滤器统一拦截所有请求,配置集中、优先级高,适配所有版本 Spring Boot,兼容性极强,适合需要精细控制跨域规则、整合权限框架的项目。

2.3 WebMvc全局配置(最常用、企业首选)

实现 WebMvcConfigurer 接口,重写跨域方法,全局统一配置所有接口跨域规则,代码简洁、无侵入、便于维护,是绝大多数前后端分离项目的标准方案,本文重点主推该方案。

2.4 配置文件跨域(极简,适合简单项目)

Spring Boot2.4+ 支持直接在 yml 配置文件配置跨域,无需编写代码,极简高效,但灵活性较低,无法适配复杂场景(多域名、动态域名、自定义请求头),仅适合小型简单项目。

三、企业级全局跨域配置(无导包、可直接落地)

本文提供两套最稳定的全局跨域方案,适配不同项目场景,二选一使用,禁止混用,彻底避免配置冲突问题。所有代码均删除导包语句,直接复制即可使用。

3.1 方案一:WebMvcConfigurer 全局跨域(推荐,通用所有场景)

该方案集中管理所有跨域规则,支持多域名、通配符域名、所有请求方法、携带Cookie与Token,自动处理OPTIONS预检请求,适配Spring Boot2.x、3.x全版本,是企业项目通用标准配置。

// 全局跨域配置类(统一解决前后端跨域问题)
@Configuration
public class CorsConfig implements WebMvcConfigurer {

    /**
     * 全局跨域规则配置
     * 适配所有接口、所有前端域名、所有请求方式,支持Token、Cookie跨域传递
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                // 适配多环境前端域名,支持通配符匹配
                .allowedOriginPatterns("http://localhost:*", "http://127.0.0.1:*")
                // 放行所有业务请求方法 + OPTIONS预检请求
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                // 放行所有自定义请求头(适配Token、自定义参数头)
                .allowedHeaders("*")
                // 允许跨域携带Cookie、Token凭证(核心配置)
                .allowCredentials(true)
                // 预检请求缓存时长(1小时,减少重复预检请求,提升联调效率)
                .maxAge(3600);
    }
}

核心配置详解:

  1. allowedOriginPatterns:替代旧版 allowedOrigins,支持通配符,解决固定域名无法适配多端口、多环境的问题,同时避免 allowCredentials=true 时通配符报错;

  2. allowedMethods包含OPTIONS:专门处理前端预检请求,彻底解决PUT/DELETE请求跨域失败问题,适配Spring Boot3.x高版本严格校验规则;

  3. allowCredentials=true:开启凭证跨域,允许前端传递Cookie、Token、Session,是登录认证、权限校验场景的必备配置。

3.2 方案二:配置文件极简跨域(适合小型项目)

无需编写Java代码,仅通过yml配置文件快速开启跨域,适配Spring Boot2.4及以上版本,简单高效,适合功能简单、无需复杂跨域规则的项目。

# 全局跨域配置(Spring Boot2.4+ 专属)
spring:
  web:
    cors:
      # 允许的前端域名(多域名用逗号分隔)
      allowed-origins: http://localhost:8080,http://127.0.0.1:8080
      # 允许的请求方法
      allowed-methods: GET,POST,PUT,DELETE,OPTIONS
      # 允许携带凭证
      allow-credentials: true
      # 预检请求缓存时间
      max-age: 3600
      # 允许所有请求头
      allowed-headers: "*"

3.3 方案三:CorsFilter 过滤器跨域(适配SpringSecurity项目)

若项目集成了SpringSecurity权限框架,普通WebMvc跨域配置会失效,必须使用过滤器方式配置跨域,否则预检请求会被安全框架拦截,联调必报错。

// SpringSecurity适配跨域配置
@Configuration
public class SecurityCorsConfig {

    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        // 允许跨域域名
        config.setAllowedOriginPatterns("http://localhost:*", "http://127.0.0.1:*");
        // 允许请求方法
        config.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE","OPTIONS"));
        // 允许请求头
        config.setAllowedHeaders(Arrays.asList("*"));
        // 允许凭证传递
        config.setAllowCredentials(true);
        // 预检缓存时间
        config.setMaxAge(3600L);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

四、前后端联调高频跨域坑点深度避坑

大部分跨域报错并非配置未生效,而是配置不规范、版本不兼容、前后端参数不匹配导致。下面整理联调过程中99%开发者都会遇到的坑点,附带完整解决方案。

坑点1:allowCredentials=true 与 * 通配符冲突报错

报错现象:开启凭证跨域后,使用 allowedOrigins("*") 全局放行域名,浏览器直接报跨域错误,无法携带Token。

原因:浏览器安全规范禁止 允许凭证 + 任意域名 同时生效,认为该组合存在极大安全风险,Spring Boot高版本直接拦截该配置。

解决方案:放弃 allowedOrigins 通配符,使用 allowedOriginPatterns 支持通配符匹配,完美兼容凭证跨域,也是目前官方推荐写法。

坑点2:PUT/DELETE 请求跨域失败,GET/POST正常

报错现象:普通查询、新增接口正常,修改、删除接口直接跨域,无业务日志输出。

原因:PUT/DELETE请求触发浏览器OPTIONS预检请求,项目未配置放行OPTIONS方法,预检请求拦截,导致真实请求无法发起;Spring Boot3.x默认仅放行GET、POST、HEAD,未手动配置会直接拦截。

解决方案:跨域配置中主动添加 OPTIONS 请求方法,全局放行预检请求。

坑点3:@CrossOrigin 注解与全局配置混用冲突

报错现象:部分接口跨域正常,部分接口随机报错,规则混乱、难以排查。

原因:注解跨域和全局跨域配置优先级不统一,相互覆盖,导致跨域规则错乱。

解决方案:项目统一使用全局跨域配置,删除所有接口上的@CrossOrigin注解,配置集中统一管理,杜绝冲突。

坑点4:跨域配置正常,携带Token后报错

报错现象:不带Token的普通请求正常,登录后携带Token请求直接跨域。

原因:未开启allowCredentials凭证跨域,或未放行自定义Authorization请求头,浏览器拦截带凭证的跨域请求。

解决方案:开启allowCredentials=true,同时通过allowedHeaders放行所有自定义请求头,确保Token可以正常传递。

坑点5:开发环境正常,生产环境跨域失效

报错现象:本地联调完全正常,部署服务器后前端页面跨域报错。

原因:全局配置仅放行localhost、127.0.0.1本地域名,未配置生产环境前端正式域名;生产环境前后端域名、端口不一致,触发跨域拦截。

解决方案:在allowedOriginPatterns中添加生产前端域名,支持多域名配置,适配多环境部署。

坑点6:SpringSecurity 拦截跨域请求

报错现象:普通接口跨域正常,需要登录认证的接口跨域报错,控制台403。

原因:SpringSecurity权限框架优先级高于WebMvc跨域配置,预检请求未携带Token,被安全拦截器拦截,导致跨域失效。

解决方案:使用CorsFilter过滤器方式配置跨域,同时在Security配置中开启跨域支持,确保安全框架放行跨域请求。

五、前后端联调标准化流程

为彻底避免联调阶段反复踩坑,整理一套标准化联调流程,适配所有前后端分离项目:

  1. 后端统一配置全局跨域,删除所有局部注解,统一跨域规则,放行所有请求方法、自定义请求头、凭证;

  2. 后端配置完成后重启项目,优先测试OPTIONS预检请求是否正常返回;

  3. 前端统一配置请求拦截器,固定请求头格式,统一携带Token,避免请求头不规范导致跨域;

  4. 开发环境使用通配符域名适配本地端口,生产环境配置正式域名,关闭全局通配符提升安全性;

  5. 结合前文接口日志功能,查看请求是否正常到达后端,区分是浏览器跨域拦截还是后端业务报错。

六、总结

跨域问题本质不是Bug,而是浏览器的安全限制,绝大多数联调跨域报错,都是配置不规范、版本不兼容、场景适配缺失导致。本文提供的三套全局跨域方案,覆盖简单项目、通用项目、权限项目全场景,彻底替代零散的注解配置。

核心避坑要点:统一全局配置、禁止多方案混用、务必放行OPTIONS预检请求、开启凭证跨域适配Token登录、区分Spring Boot版本差异、适配多环境域名。将该全局配置集成到项目中,可彻底解决前后端联调所有跨域问题,保证项目从开发到上线全程稳定可用。