当前位置: 代码网 > it编程>编程语言>Java > SpringBoot优雅解决CORS跨域问题的完整方案

SpringBoot优雅解决CORS跨域问题的完整方案

2026年08月28日 Java 我要评论
前后端分离项目,跨域是必踩的坑。本文将彻底讲清跨域的本质、spring boot 4 的 cors 解决方案、全局/局部配置、与拦截器的执行顺序,以及生产环境的安全配置。一、什么是跨域?为什么会有跨域

前后端分离项目,跨域是必踩的坑。本文将彻底讲清跨域的本质、spring boot 4 的 cors 解决方案、全局/局部配置、与拦截器的执行顺序,以及生产环境的安全配置。

一、什么是跨域?为什么会有跨域问题?

同源策略(same-origin policy)

浏览器出于安全考虑,只允许同源的资源进行交互。

同源 = 协议 + 域名 + 端口 完全相同

url是否同源原因
http://localhost:8080http://localhost:8080/api完全相同
http://localhost:8080https://localhost:8080协议不同
http://localhost:8080http://localhost:8081端口不同
http://localhost:8080http://api.example.com域名不同

跨域请求被拦截的完整流程

浏览器 → 服务器:发送请求(实际已到达服务器)
服务器 → 浏览器:返回响应
浏览器:检查响应头是否有 cors 头
  → 有:放行,交给 js
  → 没有:拦截,报错

关键点:请求已经到达服务器,只是浏览器拦截了响应!

简单请求 vs 预检请求(options)

类型触发条件浏览器行为
简单请求get / post / head + 特定 content-type直接发送
预检请求put / delete / 自定义头 / application/json先发 options,通过后再发真实请求

二、spring boot 4 解决跨域的 4 种方式

方式一:@crossorigin 注解(局部)

@restcontroller
@requestmapping("/users")
@crossorigin(origins = "http://localhost:3000")
public class usercontroller {

    @getmapping("/{id}")
    @crossorigin(origins = "http://localhost:3000", maxage = 3600)
    public result<uservo> getuser(@pathvariable long id) {
        return result.success(userservice.getbyid(id));
    }
}

缺点:每个 controller 都要加,维护成本高

方式二:全局 cors 配置(推荐)

@configuration
public class corsconfig {

    @bean
    public corsfilter corsfilter() {
        corsconfiguration config = new corsconfiguration();
        config.setallowcredentials(true);
        config.addallowedorigin("http://localhost:3000");
        config.addallowedheader("*");
        config.addallowedmethod("*");
        config.setmaxage(3600l);

        urlbasedcorsconfigurationsource source = new urlbasedcorsconfigurationsource();
        source.registercorsconfiguration("/**", config);

        return new corsfilter(source);
    }
}

方式三:webmvcconfigurer 配置(最优雅)

@configuration
public class webconfig implements webmvcconfigurer {

    @override
    public void addcorsmappings(corsregistry registry) {
        registry.addmapping("/**")
                .allowedorigins("http://localhost:3000")
                .allowedmethods("get", "post", "put", "delete", "options")
                .allowedheaders("*")
                .allowcredentials(true)
                .maxage(3600);
    }
}

企业级推荐:代码清晰、语义明确

方式四:spring security 中配置(有 security 时必用)

@configuration
@enablewebsecurity
public class securityconfig {

    @bean
    public securityfilterchain filterchain(httpsecurity http) throws exception {
        http
            .cors(cors -> cors.configurationsource(corsconfigurationsource()))
            .csrf(csrf -> csrf.disable());
        return http.build();
    }

    @bean
    public corsconfigurationsource corsconfigurationsource() {
        corsconfiguration config = new corsconfiguration();
        config.setallowcredentials(true);
        config.addallowedorigin("http://localhost:3000");
        config.addallowedheader("*");
        config.addallowedmethod("*");

        urlbasedcorsconfigurationsource source = new urlbasedcorsconfigurationsource();
        source.registercorsconfiguration("/**", config);
        return source;
    }
}

三、cors 配置项详解

配置项说明推荐值
allowedorigins允许的源具体域名,不要用 *
allowedmethods允许的 http 方法get, post, put, delete, options
allowedheaders允许的请求头* 或具体头
allowcredentials是否允许凭证(cookie)true
maxage预检请求缓存时间3600 秒

重要限制:allowcredentials = true 时,allowedorigins 不能用 *

四、cors 与 filter / interceptor 的执行顺序

完整请求处理链

浏览器请求
  ↓
filter (corsfilter)
  ↓
dispatcherservlet
  ↓
interceptor (prehandle)
  ↓
controller

cors 在 filter 阶段处理,早于 interceptor 和 controller

为什么 interceptor 中校验 token 会失败?

原因:预检请求(options)不带 token

@override
public boolean prehandle(httpservletrequest request, httpservletresponse response, object handler) {
    // ❌ options 请求会在这里被拦截
    string token = request.getheader("authorization");
    if (token == null) {
        return false;
    }
    return true;
}

正确写法:放行 options 请求

@override
public boolean prehandle(httpservletrequest request, httpservletresponse response, object handler) {
    if ("options".equals(request.getmethod())) {
        return true; // 放行预检请求
    }
    // 正常校验 token
    string token = request.getheader("authorization");
    return token != null && token.startswith("bearer ");
}

五、生产环境安全配置(重点)

不安全的配置

config.addallowedorigin("*");  // 允许所有源
config.setallowcredentials(true); // 还允许凭证 → 报错

生产级安全配置

@configuration
public class corsconfig {

    private static final list<string> allowed_origins = list.of(
            "https://www.example.com",
            "https://admin.example.com",
            "https://m.example.com"
    );

    @bean
    public corsfilter corsfilter() {
        corsconfiguration config = new corsconfiguration();
        config.setallowcredentials(true);
        config.setallowedorigins(allowed_origins); // 明确指定允许的源
        config.addallowedmethod("get");
        config.addallowedmethod("post");
        config.addallowedmethod("put");
        config.addallowedmethod("delete");
        config.addallowedmethod("options");
        config.addallowedheader("*");
        config.setmaxage(3600l);

        urlbasedcorsconfigurationsource source = new urlbasedcorsconfigurationsource();
        source.registercorsconfiguration("/api/**", config); // 只针对 api

        return new corsfilter(source);
    }
}

六、spring boot 4 中的新变化

allowedoriginpatterns 支持更完善(支持通配符模式)

aot 模式下 cors 配置处理更早

与 spring security 7 深度整合

七、常见坑位总结(血泪教训)

坑1:配置了 cors 但依然跨域报错

检查:

  • 是否有拦截器拦截了 options 请求
  • allowcredentialsallowedorigins 是否冲突
  • 前端是否真的发了请求

坑2:前端带 cookie 但后端收不到

检查:

  • 后端 allowcredentials = true
  • 前端 withcredentials = true
  • 前端 axios.defaults.withcredentials = true

坑3:spring security 中 cors 不生效

必须在 security 中配置 cors,不能只靠 webmvcconfigurer

坑4:预检请求被拦截器拦截

放行 options 请求

坑5:allowedorigins 用通配符

生产环境明确指定域名

八、本篇总结

跨域是浏览器的同源策略限制,请求已到达服务器

spring boot 4 推荐用 webmvcconfigurer 配置 cors

cors 在 filter 阶段处理,早于 interceptor

options 预检请求必须放行

生产环境明确指定允许的源,不要用 *

以上就是springboot优雅解决cors跨域问题的完整方案的详细内容,更多关于springboot解决cors跨域的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com