开发者

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

目录
  • 一、跨域问题简介
  • 二、方案一:基于@CrossOrigin注解的方法级别控制
    • 实现方式
    • 优点
    • 缺点
  • 三、方案二:全局CORS配置(WebMvcConfigurer)
    • 实现方式
    • 优点
    • 缺点
  • 四、方案三:使用CorsFilter
    • 实现方式
    • 优点
    • 缺点
  • 五、方案四:Spring Security中的CORS配置
    • 实现方式
    • 优点
    • 缺点
  • 六、方案五:网关层面解决跨域(Spring Cloud Gateway)
    • 实现方式
    • 优点
    • 缺点
  • 七、方案六:使用代理服务器
    • 前端开发服务器代理配置(以vue CLI为例)
    • Nginx反向代理配置
    • 优点
    • 缺点
  • 八、方案比较与选择建议
    • 九、最佳实践与注意事项
      • 1. 安全考虑
      • 2. 性能优化
      • 3. 开发与调试
    • 十、总结

      一、跨域问题简介

      在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&pythongt; 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://www.devze.com      
              // 允许的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.setAllowCredentiapythonls(true);
              configuration.setMaxAge(3600L);
              
              UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSo编程urce();
              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("Accessphp-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解决跨域请求的资料请关注编程客栈(www.devze.com)其它相关文章!

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜