6种SpringBoot解决跨域请求的方法整理

 更新时间:2025年04月03日 08:33:05   作者:风象南  
跨域资源共享是一种标准机制,允许服务器声明哪些源可以访问其资源,在SpringBoot应用中,有多种方式可以解决跨域问题,本文主要介绍了6种常见的解决方案,大家可以根据需求自行选择

一、跨域问题简介

在Web开发中,浏览器的同源策略(Same-Origin Policy)是一项重要的安全机制,它限制了一个源(Origin)中加载的文档或脚本如何与另一个源的资源进行交互。所谓同源,指的是协议、域名和端口号都相同。当前端应用试图请求与自身不同源的后端API时,就会遇到跨域问题。

例如,当 http://frontend.com 的前端应用尝试访问 http://backend.com/api 的后端服务时,浏览器会阻止这种请求,并在控制台报错:

Access to XMLHttpRequest at 'http://backend.com/api' from origin 'http://frontend.com' 
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

跨域资源共享(CORS,Cross-Origin Resource Sharing)是一种标准机制,允许服务器声明哪些源可以访问其资源。在SpringBoot应用中,有多种方式可以解决跨域问题,下面详细介绍6种常见的解决方案。

二、方案一:基于@CrossOrigin注解的方法级别控制

这是最简单直接的方式,通过在Controller类或特定方法上添加@CrossOrigin注解来允许跨域请求。

实现方式

// 在方法级别允许跨域
@RestController
@RequestMapping("/api")
public class UserController {
    
    @CrossOrigin(origins = "http://example.com")
    @GetMapping("/users")
    public List<User> getUsers() {
        // 方法实现
        return userService.findAll();
    }
    
    @GetMapping("/roles")
    public List<Role> getRoles() {
        // 此方法不允许跨域
        return roleService.findAll();
    }
}

// 在类级别允许跨域
@CrossOrigin(origins = {"http://example.com", "http://localhost:3000"})
@RestController
@RequestMapping("/api/products")
public class ProductController {
    
    @GetMapping
    public List<Product> getAllProducts() {
        // 方法实现
        return productService.findAll();
    }
    
    @GetMapping("/{id}")
    public Product getProduct(@PathVariable Long id) {
        // 方法实现
        return productService.findById(id);
    }
}

优点

  • 实现简单直观
  • 可以精确控制到方法级别
  • 可以针对不同的API设置不同的CORS规则

缺点

  • 代码重复,需要在多个地方添加注解
  • 维护成本高,当CORS策略变更时,需要修改多处代码
  • 不适合大型项目中统一管理CORS策略

三、方案二:全局CORS配置(WebMvcConfigurer)

通过实现WebMvcConfigurer接口并重写addCorsMappings方法,可以在全局范围内配置CORS规则。

实现方式

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("http://example.com", "http://localhost:3000")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600); // 1小时内不需要再预检(发OPTIONS请求)
    }
}

优点

  • 可以方便集中管理所有API的CORS配置
  • 配置灵活,可以针对不同的URL模式设置不同的规则
  • 代码简洁,易于维护

缺点

  • 在某些场景下可能需要与其他安全配置结合使用

四、方案三:使用CorsFilter

通过定义CorsFilter作为一个Bean,可以在过滤器级别处理跨域请求,这种方式比WebMvcConfigurer的优先级更高。

实现方式

@Configuration
public class CorsConfig {
    
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        
        // 允许的源
        config.addAllowedOrigin("http://example.com");
        config.addAllowedOrigin("http://localhost:3000");
        
        // 允许的HTTP方法
        config.addAllowedMethod("*");
        
        // 允许的头信息
        config.addAllowedHeader("*");
        
        // 允许携带认证信息(Cookie等)
        config.setAllowCredentials(true);
        
        // 预检请求的有效期,单位为秒
        config.setMaxAge(3600L);
        
        // 对所有URL应用这些配置
        source.registerCorsConfiguration("/**", config);
        
        return new CorsFilter(source);
    }
}

优点

  • 在过滤器级别处理,可以拦截所有请求
  • 优先级高于方案二
  • 可以与其他过滤器组合使用
  • 适合在不修改已有Controller的情况下添加CORS支持

缺点

  • 无法精确到方法级别控制
  • 对于复杂的规则可能不够灵活

五、方案四:Spring Security中的CORS配置

如果项目使用了Spring Security,需要在Security配置中允许CORS,否则Security可能会拦截跨域请求。

实现方式

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .cors(Customizer.withDefaults()) // 使用CorsConfigurationSource的默认配置
            .csrf().disable()
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers("/api/**").authenticated()
                .anyRequest().permitAll()
            )
            .httpBasic(Customizer.withDefaults());
        
        return http.build();
    }
    
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://example.com", "http://localhost:3000"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type"));
        configuration.setAllowCredentials(true);
        configuration.setMaxAge(3600L);
        
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

优点

  • 与Spring Security无缝集成
  • 可以结合认证和授权规则一起配置
  • 适合需要安全控制的REST API

缺点

  • 依赖Spring Security
  • 对于不需要安全控制的简单应用可能略显复杂

六、方案五:网关层面解决跨域(Spring Cloud Gateway)

在微服务架构中,可以在API网关层统一处理跨域问题,这样后端微服务就不需要各自配置CORS了。

实现方式

// Spring Cloud Gateway配置
@Configuration
public class GatewayConfig {
    
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("user_service_route", r -> r.path("/api/users/**")
                        .uri("lb://user-service"))
                .route("product_service_route", r -> r.path("/api/products/**")
                        .uri("lb://product-service"))
                .build();
    }
    
    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request)) {
                ServerHttpResponse response = ctx.getResponse();
                HttpHeaders headers = response.getHeaders();
                headers.add("Access-Control-Allow-Origin", "*");
                headers.add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
                headers.add("Access-Control-Allow-Headers", "Authorization, Content-Type");
                headers.add("Access-Control-Allow-Credentials", "true");
                headers.add("Access-Control-Max-Age", "3600");
                if (request.getMethod() == HttpMethod.OPTIONS) {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }
}

优点

  • 集中处理所有微服务的跨域问题
  • 后端服务无需关心跨域配置
  • 便于统一管理和维护
  • 适合微服务架构

缺点

  • 依赖Spring Cloud Gateway
  • 配置相对复杂
  • 对于单体应用可能过于重量级

七、方案六:使用代理服务器

通过配置前端开发服务器代理 (开发环境) 或使用Nginx (生产环境) 等反向代理服务器,可以间接解决跨域问题。这种方式实际上是绕过了浏览器的同源策略,而不是直接在后端解决CORS。

前端开发服务器代理配置(以Vue CLI为例)

// vue.config.js
module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        pathRewrite: {
          '^/api': '/api'
        }
      }
    }
  }
}

Nginx反向代理配置

server {
    listen 80;
    server_name frontend.example.com;
    
    location / {
        root /usr/share/nginx/html;
        index index.html;
        try_files $uri $uri/ /index.html;
    }
    
    location /api/ {
        proxy_pass http://backend.example.com:8080/api/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

优点

  • 完全绕过浏览器的同源策略限制
  • 后端无需任何CORS配置

缺点

  • 需要额外的代理配置
  • 增加了系统复杂性
  • 可能引入额外的网络延迟

八、方案比较与选择建议

方案实现难度灵活性维护成本适用场景
@CrossOrigin注解小型项目,特定API需要跨域
WebMvcConfigurer大多数Spring Boot应用
CorsFilter需要优先级高的CORS处理
Spring Security有安全需求的应用
网关层面解决微服务架构
代理服务器生产环境,严格的安全要求

九、最佳实践与注意事项

1. 安全考虑

  • 不要盲目设置Access-Control-Allow-Origin: *,应该明确指定允许的源
  • 谨慎处理带有凭证的请求(如Cookie),确保只允许受信任的源
  • 对于敏感操作,考虑使用CSRF令牌进行保护

2. 性能优化

  • 合理设置Access-Control-Max-Age以减少预检请求
  • 避免在每个请求中都解析和构建CORS头
  • 在网关层处理CORS可以减轻后端服务的负担

3. 开发与调试

  • 在开发环境可以适当放宽CORS限制,但在生产环境一定要收紧
  • 使用浏览器开发者工具的Network面板调试CORS问题

十、总结

跨域请求是前后端分离开发中不可避免的问题,Spring Boot提供了多种解决方案。从简单的@CrossOrigin注解到复杂的网关配置,我们可以根据项目规模和需求选择合适的方案。在实际开发中,建议综合考虑安全性、灵活性和维护成本,选择最适合项目的CORS解决方案。

对于大多数Spring Boot应用,推荐使用全局CORS配置(WebMvcConfigurer)方案,它提供了良好的平衡性;而对于微服务架构,则推荐在网关层统一处理CORS问题,以减少后端服务的配置负担。

无论选择哪种方案,都应该遵循"最小权限原则" ,只允许必要的源访问必要的资源,确保系统的安全性。

以上就是6种SpringBoot解决跨域请求的方法整理的详细内容,更多关于SpringBoot解决跨域请求的资料请关注脚本之家其它相关文章!

相关文章

  • 一口气说出Java 6种延时队列的实现方法(面试官也得服)

    一口气说出Java 6种延时队列的实现方法(面试官也得服)

    这篇文章主要介绍了一口气说出Java 6种延时队列的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • Feign使用@PathVariable方式

    Feign使用@PathVariable方式

    Feign使用@PathVariable注解在URL中插入变量,类似于SpringMVC的用法,通过示例展示了如何使用该注解,并在实际调用中替换占位符
    2024-11-11
  • Spring Boot 中application.yml与bootstrap.yml的区别

    Spring Boot 中application.yml与bootstrap.yml的区别

    其实yml和properties文件是一样的原理,且一个项目上要么yml或者properties,二选一的存在。这篇文章给大家介绍了Spring Boot 中application.yml与bootstrap.yml的区别,感兴趣的朋友一起看看吧
    2018-04-04
  • 超详细解释Java反射

    超详细解释Java反射

    本文非常详细的讲解了java反射具体的内容以及使用,java反射在现今的使用中很频繁,希望此文可以帮大家解答疑惑,可以帮助大家理解
    2021-11-11
  • SpringBoot搭配AOP实现自定义注解

    SpringBoot搭配AOP实现自定义注解

    这篇文章主要为大家详细介绍了SpringBoot如何搭配AOP实现自定义注解,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-12-12
  • Java8不可或缺小帮手之日期应用

    Java8不可或缺小帮手之日期应用

    jdk1.8后引入了新的日期时间处理API,相比传统的date操作更加简便,date中的SimpleDateFormat也是非线程安全的,废话不多说,开干
    2023-05-05
  • Java中十六进制和十进制之间互相转换代码示例

    Java中十六进制和十进制之间互相转换代码示例

    这篇文章主要给大家介绍了关于Java中十六进制和十进制之间互相转换的相关资料,我们项目过程中总是要用到十进制与十六进制相互转换的方法,需要的朋友可以参考下
    2023-07-07
  • Spring循环依赖正确性及Bean注入的顺序关系详解

    Spring循环依赖正确性及Bean注入的顺序关系详解

    这篇文章主要给大家介绍了关于Spring循环依赖的正确性,以及Bean注入的顺序关系的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-01-01
  • Spring JPA学习之delete方法示例详解

    Spring JPA学习之delete方法示例详解

    这篇文章主要为大家介绍了Spring JPA学习delete方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • Kryo框架使用方法代码示例

    Kryo框架使用方法代码示例

    这篇文章主要介绍了Kryo框架的相关内容,文中向大家分享了Kryo框架使用方法代码示例,小编觉得挺不错的,希望能给大家一个参考。
    2017-10-10

最新评论