一、cors基础概念
1. 什么是跨域请求?
当浏览器从一个域名的网页去请求另一个域名的资源时,如果域名、端口或协议不同,就会产生跨域请求。出于安全考虑,浏览器默认会阻止这类请求。
2. 简单请求 vs 预检请求
类型 | 条件 | 处理方式 |
---|---|---|
简单请求 | get/head/post方法,且content-type为text/plain、multipart/form-data或application/x-www-form-urlencoded | 直接发送请求,带origin头 |
预检请求(options) | 不符合简单请求条件的其他请求 | 先发送options请求,获得许可后再发送实际请求 |
二、spring boot处理cors的5种方式
1. 使用@crossorigin注解
适用场景:针对单个控制器或方法级别的cors配置
@restcontroller @requestmapping("/api") public class mycontroller { // 允许特定源的跨域访问 @crossorigin(origins = "https://example.com") @getmapping("/resource") public responseentitygetresource() { return responseentity.ok("跨域资源"); } // 更详细的配置 @crossorigin(origins = {"https://example.com", "https://api.example.com"}, allowedheaders = {"content-type", "authorization"}, methods = {requestmethod.get, requestmethod.post}, maxage = 3600) @postmapping("/save") public responseentity saveresource() { return responseentity.ok("保存成功"); } }
2. 全局cors配置
适用场景:应用级别的统一cors配置
@configuration public class webconfig implements webmvcconfigurer { @override public void addcorsmappings(corsregistry registry) { registry.addmapping("/api/**") // 匹配的路径 .allowedorigins("https://example.com", "https://api.example.com") // 允许的源 .allowedmethods("get", "post", "put", "delete") // 允许的方法 .allowedheaders("*") // 允许的请求头 .exposedheaders("authorization", "content-disposition") // 暴露的响应头 .allowcredentials(true) // 是否允许发送cookie .maxage(3600); // 预检请求缓存时间(秒) // 可以添加多个配置 registry.addmapping("/public/**") .allowedorigins("*"); } }
3. 使用filter处理cors
适用场景:需要更底层控制或与非spring web环境集成
@configuration public class corsfilterconfig { @bean public filterregistrationbeancorsfilter() { urlbasedcorsconfigurationsource source = new urlbasedcorsconfigurationsource(); corsconfiguration config = new corsconfiguration(); // 配置cors规则 config.setallowcredentials(true); config.addallowedorigin("https://example.com"); config.addallowedheader("*"); config.addallowedmethod("*"); config.setmaxage(3600l); // 对所有路径生效 source.registercorsconfiguration("/**", config); filterregistrationbean bean = new filterregistrationbean<>(new corsfilter(source)); bean.setorder(ordered.highest_precedence); // 设置最高优先级 return bean; } }
4. spring security中的cors配置
适用场景:使用spring security的项目
@configuration @enablewebsecurity public class securityconfig extends websecurityconfigureradapter { @override protected void configure(httpsecurity http) throws exception { http.cors().and() // 启用cors支持 .csrf().disable() // 通常cors和csrf不能同时使用 .authorizerequests() .antmatchers("/api/public/**").permitall() .anyrequest().authenticated(); } // 提供cors配置源 @bean corsconfigurationsource corsconfigurationsource() { corsconfiguration configuration = new corsconfiguration(); configuration.setallowedorigins(arrays.aslist("https://example.com")); configuration.setallowedmethods(arrays.aslist("get", "post")); configuration.setallowedheaders(arrays.aslist("*")); urlbasedcorsconfigurationsource source = new urlbasedcorsconfigurationsource(); source.registercorsconfiguration("/**", configuration); return source; } }
5. 响应头手动设置
适用场景:需要动态控制cors头
@restcontroller public class dynamiccorscontroller { @getmapping("/dynamic-cors") public responseentitydynamiccors(httpservletrequest request, httpservletresponse response) { // 根据请求动态设置cors头 string origin = request.getheader("origin"); if (isallowedorigin(origin)) { response.setheader("access-control-allow-origin", origin); response.setheader("access-control-allow-credentials", "true"); response.setheader("access-control-allow-methods", "get, post"); } return responseentity.ok("动态cors响应"); } private boolean isallowedorigin(string origin) { // 实现你的源验证逻辑 return origin != null && origin.endswith("example.com"); } }
三、cors配置详解
1. 核心响应头说明
响应头 | 说明 |
---|---|
access-control-allow-origin | 允许访问的源,可以是具体域名或*(不推荐使用*,特别是需要凭证时) |
access-control-allow-methods | 允许的http方法(get, post等) |
access-control-allow-headers | 允许的请求头 |
access-control-expose-headers | 浏览器可以访问的响应头 |
access-control-allow-credentials | 是否允许发送cookie(true/false),设为true时allow-origin不能为* |
access-control-max-age | 预检请求结果的缓存时间(秒) |
2. 常见问题解决方案
问题1:预检请求(options)被拦截
解决方案:
- 确保options请求不被安全框架拦截
- 在spring security中配置:
http.cors().and() .authorizerequests() .antmatchers(httpmethod.options, "/**").permitall()
问题2:带凭证的请求失败
解决方案:
- 确保
allowcredentials(true)
和具体的allowedorigins
(不能是*) - 前端需要设置
withcredentials: true
(如axios)
问题3:特定响应头无法获取
解决方案:
- 使用
exposedheaders
暴露需要的头:
.exposedheaders("custom-header", "authorization")
四、最佳实践建议
- 生产环境不要使用通配符*:明确指定允许的源
- 合理限制http方法:只开放必要的方法(get/post等)
- 考虑使用环境变量:动态配置允许的源
@value("${cors.allowed.origins}") private string[] allowedorigins; // 在配置中使用 .allowedorigins(allowedorigins)
- 结合安全框架:spring security项目使用专门的cors配置
- 测试不同场景:简单请求和预检请求都要测试
五、完整配置示例
@configuration @enablewebmvc public class corsconfig implements webmvcconfigurer { @value("${app.cors.allowed-origins}") private string[] allowedorigins; @override public void addcorsmappings(corsregistry registry) { registry.addmapping("/api/**") .allowedorigins(allowedorigins) .allowedmethods("get", "post", "put", "patch", "delete", "options") .allowedheaders("*") .exposedheaders("authorization", "content-disposition") .allowcredentials(true) .maxage(3600); registry.addmapping("/public/**") .allowedorigins("*") .allowedmethods("get", "options"); } // 可选:提供cors过滤器作为备选 @bean public filterregistrationbeancorsfilter() { urlbasedcorsconfigurationsource source = new urlbasedcorsconfigurationsource(); corsconfiguration config = new corsconfiguration(); config.applypermitdefaultvalues(); config.setallowcredentials(true); config.setallowedorigins(arrays.aslist(allowedorigins)); source.registercorsconfiguration("/**", config); filterregistrationbean bean = new filterregistrationbean<>(new corsfilter(source)); bean.setorder(ordered.highest_precedence); return bean; } }
六、总结
spring boot提供了多种灵活的方式来处理cors:
- 简单场景:使用
@crossorigin
注解 - 统一配置:实现
webmvcconfigurer
的addcorsmappings
方法 - 底层控制:配置
corsfilter
- 安全项目:结合spring security的
cors()
配置 - 动态需求:手动设置响应头
根据项目需求选择合适的方式,并遵循安全最佳实践,可以有效地解决跨域问题,同时保证应用的安全性。
以上就是springboot处理跨域请求(cors)的五种方式的详细内容,更多关于springboot处理跨域请求的资料请关注代码网其它相关文章!
海报
156