Spring Boot跨域请求又被拦截了?这5种解决方案让你彻底告别CORS错误!

Spring Boot跨域请求又被拦截了?这5种解决方案让你彻底告别CORS错误!

本文来自公众号【服务端技术精选】,专注Java后端技术干货分享

大家好,我是你们的老朋友,一个在后端摸爬滚打了多年的老程序员。今天我们来聊聊一个让无数前端后端程序员都头疼的问题——跨域请求!

相信很多小伙伴在做前后端分离项目的时候,都被那个红彤彤的跨域错误折磨过。什么"CORS policy"、"blocked by CORS policy",看得人一脸懵逼。今天我就带大家彻底搞懂这个问题,让你从此告别跨域烦恼!

什么是跨域?为什么会有跨域限制?

首先我们要明白,跨域其实是一种安全机制,叫做"同源策略"。那什么叫"同源"呢?

简单来说,就是两个URL的协议、域名、端口都相同才算同源。比如:

  • http://www.example.com:8080http://www.example.com:8080 是同源的
  • http://www.example.com:8080https://www.example.com:8080 就不是同源的(协议不同)
  • http://www.example.com:8080http://api.example.com:8080 也不是同源的(域名不同)
  • http://www.example.com:8080http://www.example.com:9090 也不是同源的(端口不同)

浏览器出于安全考虑,默认情况下不允许跨域请求。这就是为什么你在本地开发时,前端跑在3000端口,后端跑在8080端口,就会出现跨域问题。

Spring Boot中解决跨域的5种方法

方法一:使用@CrossOrigin注解(最简单)

这是最简单直接的方法,适合快速开发:

@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:3000")
public class UserController {
    
    @GetMapping("/users")
    public List<User> getUsers() {
        return userService.getAllUsers();
    }
}

如果你想对整个Controller都开启跨域,可以直接加在类上;如果只想对某个方法开启,就加在方法上。

方法二:全局配置类(最灵活)

这种方法适合需要统一管理跨域配置的项目:

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("http://localhost:3000", "https://www.yourdomain.com")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

方法三:使用Filter过滤器(最底层)

如果你需要更底层的控制,可以使用Filter:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        
        response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }
}

方法四:application.yml配置(最简洁)

在配置文件中也可以配置跨域:

spring:
  web:
    cors:
      allowed-origins: 
        - "http://localhost:3000"
        - "https://www.yourdomain.com"
      allowed-methods:
        - GET
        - POST
        - PUT
        - DELETE
        - OPTIONS
      allowed-headers: "*"
      allow-credentials: true
      max-age: 3600

方法五:WebFlux配置(响应式编程)

如果你的项目使用了WebFlux,可以这样配置:

@Configuration
public class CorsConfig {
    
    @Bean
    public CorsWebFilter corsWebFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("http://localhost:3000");
        config.addAllowedMethod("*");
        config.addAllowedHeader("*");
        config.setAllowCredentials(true);
        
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        
        return new CorsWebFilter(source);
    }
}

实际应用案例和最佳实践

电商项目前后端分离架构

假设我们正在开发一个电商项目,前端用Vue,后端用Spring Boot:

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    
    @Value("${cors.allowed.origins}")
    private String[] allowedOrigins;
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins(allowedOrigins)
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

配置文件:

cors:
  allowed:
    origins: 
      - "http://localhost:8080"
      - "https://shop.yourdomain.com"
      - "https://admin.yourdomain.com"

微服务架构中的跨域处理

在微服务架构中,我们可以把跨域配置放在网关层:

@Configuration
public class GatewayCorsConfig {
    
    @Bean
    public CorsWebFilter corsWebFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOriginPatterns(Arrays.asList("*"));
        config.addAllowedMethod("*");
        config.addAllowedHeader("*");
        config.setAllowCredentials(true);
        
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        
        return new CorsWebFilter(source);
    }
}

多域名支持的复杂配置

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 开发环境
        registry.addMapping("/api/dev/**")
                .allowedOriginPatterns("http://localhost:*")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowCredentials(true);
                
        // 生产环境
        registry.addMapping("/api/prod/**")
                .allowedOrigins("https://www.yourdomain.com", "https://admin.yourdomain.com")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowCredentials(true);
    }
}

最佳实践建议

  1. 安全性考虑:永远不要在生产环境中使用allowedOrigins("*"),这会带来安全风险。

  2. 性能优化:合理设置maxAge参数,避免浏览器频繁发送预检请求。

  3. 日志记录:在生产环境中添加详细的日志记录,便于问题排查。

  4. 配置管理:通过配置文件管理不同环境的跨域配置。

常见问题排查和解决方案

配置不生效问题

首先检查配置类是否被正确加载:

@Component
public class CorsConfigChecker implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("CORS配置已加载!");
    }
}

预检请求403错误

在拦截器中放行OPTIONS请求:

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    // 放行OPTIONS预检请求
    if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
        response.setStatus(HttpServletResponse.SC_OK);
        return true;
    }
    return super.preHandle(request, response, handler);
}

Cookie无法传递问题

前端配置:

// 前端axios配置
axios.defaults.withCredentials = true;

后端配置:

.allowedOrigins("https://www.yourdomain.com") // 不能用*
.allowCredentials(true)

总结和进阶建议

今天我们详细讲解了Spring Boot中处理跨域请求的5种方法,每种方法都有自己的适用场景:

  1. @CrossOrigin注解 - 最简单,适合快速开发
  2. 全局配置类 - 最灵活,适合复杂的业务场景
  3. Filter过滤器 - 最底层,适合需要精细控制的场景
  4. application.yml配置 - 最简洁,适合配置驱动的项目
  5. WebFlux配置 - 最新潮,适合响应式编程项目

在实际项目中,我建议大家遵循以下原则:

安全第一:永远不要在生产环境中使用通配符配置,一定要明确指定允许访问的域名。

性能优化:合理设置maxAge参数,避免浏览器频繁发送预检请求。

配置统一:将CORS配置集中管理,通过配置文件来控制不同环境的配置。

日志完善:在生产环境中添加详细的日志记录,便于问题排查和监控。

跨域问题看似简单,但在实际项目中却经常给我们带来困扰。希望通过这篇文章,大家能够彻底掌握Spring Boot中处理CORS的各种方法,并能在实际工作中灵活运用。

记住一句话:技术的学习不是为了应付面试,而是为了解决实际问题。希望大家都能成为解决问题的高手!

如果觉得这篇文章对你有帮助,别忘了点赞、转发,让更多需要的兄弟看到。我们下期再见!

欢迎关注公众号【服务端技术精选】,每周分享实用的后端技术干货!


标题:Spring Boot跨域请求又被拦截了?这5种解决方案让你彻底告别CORS错误!
作者:jiangyi
地址:http://jiangyi.space/articles/2025/12/21/1766304282928.html

    0 评论
avatar