欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

SpringBoot处理跨域请求(CORS)的五种方式,

来源: javaer 分享于  点击 29925 次 点评:140

SpringBoot处理跨域请求(CORS)的五种方式,


目录
  • 一、CORS基础概念
    • 1. 什么是跨域请求?
    • 2. 简单请求 vs 预检请求
  • 二、Spring Boot处理CORS的5种方式
    • 1. 使用@CrossOrigin注解
    • 2. 全局CORS配置
    • 3. 使用Filter处理CORS
    • 4. Spring Security中的CORS配置
    • 5. 响应头手动设置
  • 三、CORS配置详解
    • 1. 核心响应头说明
    • 2. 常见问题解决方案
      • 问题1:预检请求(OPTIONS)被拦截
      • 问题2:带凭证的请求失败
      • 问题3:特定响应头无法获取
  • 四、最佳实践建议
    • 五、完整配置示例
      • 六、总结

        一、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 ResponseEntity<String> getResource() {
                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<String> 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 FilterRegistrationBean<CorsFilter> corsFilter() {
                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<CorsFilter> 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 ResponseEntity<String> dynamicCors(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 FilterRegistrationBean<CorsFilter> corsFilter() {
                UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
                CorsConfiguration config = new CorsConfiguration();
                config.applyPermitDefaultValues();
                config.setAllowCredentials(true);
                config.setAllowedOrigins(Arrays.asList(allowedOrigins));
                source.registerCorsConfiguration("/**", config);
                
                FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
                bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
                return bean;
            }
        }
        

        六、总结

        Spring Boot提供了多种灵活的方式来处理CORS:

        1. 简单场景:使用@CrossOrigin注解
        2. 统一配置:实现WebMvcConfigureraddCorsMappings方法
        3. 底层控制:配置CorsFilter
        4. 安全项目:结合Spring Security的cors()配置
        5. 动态需求:手动设置响应头

        根据项目需求选择合适的方式,并遵循安全最佳实践,可以有效地解决跨域问题,同时保证应用的安全性。

        以上就是SpringBoot处理跨域请求(CORS)的五种方式的详细内容,更多关于SpringBoot处理跨域请求的资料请关注3672js教程其它相关文章!

        您可能感兴趣的文章:
        • SpringBoot中处理跨域请求CORS的全面指南
        • SpringBoot处理跨域请求的四种方法
        • SpringBoot开发技巧之如何处理跨域请求CORS
        • Springboot处理配置CORS跨域请求时碰到的坑
        • Springboot处理CORS跨域请求的三种方法
        相关栏目:

        用户点评