Springboot如何解决跨域问题?
- Springboot如何解决跨域问题?
- 一、先搞懂:为什么会有跨域?
- 1.1 同源的定义
- 1.2 跨域的表现
- 二、方案1:JSONP(基本不用)
- 2.1 原理
- 2.2 实战代码
- 后端接口
- 前端测试
- 2.3 适用场景
- 三、方案2:全局配置(WebMvcConfigurer)
- 3.1 原理
- 3.2 实战代码
- 全局配置类
- 测试接口
- 前端测试(Axios)
- 3.3 适用场景
- 四、方案3:CorsFilter(官方Filter方案)
- 4.1 原理
- 4.2 实战代码
- 配置类
- 4.3 适用场景
- 五、方案4:局部配置(@CrossOrigin注解)
- 5.1 原理
- 5.2 实战代码
- 单个接口配置
- Controller级配置
- 5.3 适用场景
- 六、方案对比与选型建议
Springboot如何解决跨域问题?
在前后端分离架构中,跨域问题是Java开发者绕不开的“基础门槛”。本文从跨域的本质(同源策略)出发,系统讲解SpringBoot中5种主流跨域方案,每个方案包含原理解析+可运行代码+适用场景,帮你彻底解决跨域问题。
一、先搞懂:为什么会有跨域?
跨域的根源是浏览器的同源策略(Same-Origin Policy)——这是浏览器的安全机制,要求请求的“源”必须与当前页面的“源”完全一致,才允许交互。也就是说在两个后端之间互相调用接口是没有跨域问题的。
1.1 同源的定义
“源”由三部分组成,三者完全相同才叫“同源”:
- 协议(如
http/https) - 域名(如
localhost/www.xxx.com) - 端口(如
8080/8090)
示例:当前页面是http://localhost:8080,以下请求会被判定为跨域:
https://localhost:8080(协议不同)http://127.0.0.1:8080(域名不同)http://localhost:8090(端口不同)
1.2 跨域的表现
浏览器会拦截跨域请求,控制台抛出类似错误:
Access to XMLHttpRequest at 'http://localhost:8081/api' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.二、方案1:JSONP(基本不用)
JSONP是早期跨域方案,前端后端需要同时更改,需要增加一个callback请求参数,当然这个callback参数也可以自定义。
2.1 原理
- 前端通过
<script>标签请求后端接口,传递回调函数名(如callback=handleData); - 后端将数据包裹在回调函数中返回(如
handleData({"msg":"success"})); - 前端提前定义回调函数,接收并处理数据。
2.2 实战代码
后端接口
importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.RestController;@RestControllerpublicclassJsonpController{/** * JSONP接口:接收前端传递的callback参数,返回包裹后的JSON */@GetMapping("/info")publicStringjsonpInfo(@RequestParamStringcallback){// 模拟返回的数据(比如根据id=16查询到的信息)Stringdata="{\"code\":200,\"msg\":\"success\",\"data\":{\"id\":16,\"name\":\"测试数据\",\"desc\":\"JSONP跨域示例\"}}";// 拼接JSONP格式的响应(回调函数名 + 数据)returncallback+"("+data+")";}}前端测试
<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><title>jQuery Ajax JSONP跨域示例</title><!-- 引入jQuery --><scriptsrc="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script></head><body><buttonid="submitBtn">发起JSONP请求</button><script>$("#submitBtn").click(function(){$.ajax({url:'http://localhost:8080/info?id=16',// 后端接口地址(带参数id=16)type:'GET',// JSONP仅支持GET请求dataType:'jsonp',// 关键:指定数据类型为jsonpjsonp:'callback',// 告诉后端:前端用callback参数传递回调函数名(默认就是callback,可省略)success:function(response){// 成功接收后端返回的数据console.log("JSONP请求成功,返回数据:",response);alert("请求成功!数据ID:"+response.data.id+",名称:"+response.data.name);},error:function(err){console.error("JSONP请求失败:",err);alert("请求失败,请检查控制台");}});});</script></body></html>2.3 适用场景
仅适用于简单GET请求,或需要兼容老旧浏览器(如IE)的场景,不推荐现代项目使用。
三、方案2:全局配置(WebMvcConfigurer)
这是SpringBoot中最常用、最优雅的跨域方案,通过配置全局CORS规则实现。
3.1 原理
基于W3C的CORS标准,服务端通过响应头告知浏览器“允许哪些源的请求”,核心响应头包括:
Access-Control-Allow-Origin:允许的跨域源;Access-Control-Allow-Methods:允许的请求方法;Access-Control-Allow-Credentials:是否允许携带Cookie。
3.2 实战代码
全局配置类
importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.CorsRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;@ConfigurationpublicclassGlobalCorsConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddCorsMappings(CorsRegistryregistry){registry.addMapping("/**")// 匹配所有接口.allowedOriginPatterns("*")// 允许所有源(生产环境建议指定域名).allowedMethods("GET","POST","PUT","DELETE")// 允许的请求方法.allowedHeaders("*")// 允许所有请求头.allowCredentials(true)// 允许携带Cookie.maxAge(3600);// 预检请求缓存1小时}}测试接口
@RestControllerpublicclassTestController{@GetMapping("/api/test/get")publicStringtestGet(){return"GET跨域成功";}@PostMapping("/api/test/post")publicStringtestPost(@RequestBodyStringdata){return"POST跨域成功,接收:"+data;}}前端测试(Axios)
<scriptsrc="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><buttononclick="axios.get('http://localhost:8080/api/test/get').then(res=>alert(res.data))">测试GET</button><buttononclick="axios.post('http://localhost:8080/api/test/post',{name:'张三'}).then(res=>alert(res.data))">测试POST</button>3.3 适用场景
前后端分离的现代项目,推荐作为默认方案使用。
四、方案3:CorsFilter(官方Filter方案)
通过Spring官方的CorsFilter实现跨域,比手动写Filter更规范、更灵活。
4.1 原理
CorsFilter是Spring封装的CORS过滤器,通过CorsConfiguration配置规则,再绑定到指定路径,自动拦截请求并添加跨域响应头。
4.2 实战代码
配置类
importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.cors.CorsConfiguration;importorg.springframework.web.cors.UrlBasedCorsConfigurationSource;importorg.springframework.web.filter.CorsFilter;importjava.util.Collections;@ConfigurationpublicclassCorsFilterConfig{@BeanpublicCorsFiltercorsFilter(){// 1. 配置跨域规则CorsConfigurationconfig=newCorsConfiguration();config.setAllowedOriginPatterns(Collections.singletonList("*"));config.addAllowedHeader(CorsConfiguration.ALL);config.addAllowedMethod(CorsConfiguration.ALL);config.setAllowCredentials(true);config.setMaxAge(3600L);// 2. 绑定路径UrlBasedCorsConfigurationSourcesource=newUrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**",config);// 所有路径应用规则// 3. 返回CorsFilterreturnnewCorsFilter(source);}}4.3 适用场景
需要更灵活的跨域逻辑(如动态调整跨域规则),或项目中已使用Filter链的场景。
五、方案4:局部配置(@CrossOrigin注解)
仅为个别接口/Controller配置跨域,优先级高于全局配置。
5.1 原理
@CrossOrigin是Spring提供的注解,底层基于CORS机制,为标注的接口自动添加跨域响应头。
5.2 实战代码
单个接口配置
@RestControllerpublicclassCrossOriginController{@CrossOrigin(origins="*",maxAge=3600)@GetMapping("/api/cross/test")publicStringcrossTest(){return"单个接口跨域成功";}}Controller级配置
@CrossOrigin(origins="http://localhost:8080")// 仅允许8080源@RestControllerpublicclassCrossOriginController2{@GetMapping("/api/cross/test2")publicStringcrossTest2(){return"Controller级跨域成功";}}5.3 适用场景
个别接口需要单独配置跨域的场景,不推荐全局使用。
六、方案对比与选型建议
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| JSONP | 简单GET请求、兼容老旧浏览器 | 实现简单 | 仅支持GET、有安全风险 |
| WebMvcConfigurer | 前后端分离全局跨域 | 优雅简洁、易维护 | 灵活性稍弱 |
| CorsFilter | 复杂跨域规则、Filter链场景 | 灵活可控、官方规范 | 代码量略多 |
| @CrossOrigin | 个别接口/Controller跨域 | 局部配置、无需全局修改 | 不适合全局场景 |