当前位置:首页 > 技术 > 正文内容

Java Web开发中CORS跨域问题的深度解析与实战配置

访客 技术 2026年7月26日 1

一、Spring Boot 环境下的 CORS 全局配置

在 Spring Boot 项目中,处理跨域资源共享(CORS)通常有两种主流的全局配置方式。开发者可根据项目的具体架构选择最合适的方案。

1. 基于 WebMvcConfigurer 的映射配置

通过实现 WebMvcConfigurer 接口并重写 addCorsMappings 方法,可以快速完成跨域规则的定义。

@Configuration
public class WebCorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOriginPatterns("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .allowCredentials(true)
                .exposedHeaders(HttpHeaders.AUTHORIZATION)
                .maxAge(7200);
    }
}

2. 基于 CorsFilter 的 Bean 注册

如果项目中使用了 Spring Security 或需要更底层的控制,直接注册 CorsFilter 是更稳妥的选择。

@Configuration
public class FilterCorsConfig {

    @Bean
    public FilterRegistrationBean<CorsFilter> corsFilterRegistration() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOriginPattern("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        config.setMaxAge(3600L);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        
        FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return bean;
    }
}

二、传统 SSM 架构的 CORS 处理

在传统的 Spring + SpringMVC + MyBatis (SSM) 架构中,由于缺乏 Spring Boot 的自动配置能力,我们需要手动编写 Servlet 过滤器并在 web.xml 中进行注册。

1. 编写自定义跨域过滤器

public class LegacyCorsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
            throws IOException, ServletException {
        
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        httpResponse.setHeader("Access-Control-Allow-Origin", httpRequest.getHeader("Origin"));
        httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        httpResponse.setHeader("Access-Control-Max-Age", "3600");
        httpResponse.setHeader("Access-Control-Allow-Headers", 
                "Content-Type, Authorization, X-Requested-With, Accept, Origin");
        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");

        // 针对浏览器发起的 OPTIONS 预检请求,直接返回 200 状态码
        if ("OPTIONS".equalsIgnoreCase(httpRequest.getMethod())) {
            httpResponse.setStatus(HttpServletResponse.SC_OK);
            return;
        }

        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) {}

    @Override
    public void destroy() {}
}

2. 在 web.xml 中注册过滤器

<filter>
    <filter-name>legacyCorsFilter</filter-name>
    <filter-class>com.example.config.LegacyCorsFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>legacyCorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

三、Spring Boot 中 CORS 配置失效的排查与修复

在实际开发中,经常会遇到全局 CORS 配置不生效的问题。这通常是因为项目中的自定义拦截器(Interceptor)或安全过滤器拦截了请求,且未正确传递 CORS 响应头。以下是几种有效的修复策略。

策略 1:提升 CORS 过滤器的执行优先级

确保 CORS 过滤器在所有自定义拦截器之前执行。可以通过 FilterRegistrationBean 设置最高优先级。

@Bean
public FilterRegistrationBean<CorsFilter> prioritizedCorsFilter() {
    CorsConfiguration config = new CorsConfiguration();
    config.addAllowedOriginPattern("*");
    config.setAllowCredentials(true);
    config.addAllowedMethod("*");
    config.addAllowedHeader("*");

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);

    FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
    // 设置最高优先级,确保在 Token 校验等拦截器之前执行
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE); 
    return bean;
}

策略 2:在自定义拦截器中手动注入 CORS 响应头

如果某些业务拦截器(如 Token 鉴权拦截器)必须在 CORS 过滤器之前执行,或者拦截器直接阻断了请求(如返回 401),则需要在拦截器内部手动添加跨域头。

public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 手动注入跨域响应头
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");

        // 放行 OPTIONS 预检请求
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            return false;
        }

        // 业务鉴权逻辑
        String token = request.getHeader("Authorization");
        if (token == null || !validateToken(token)) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"error\":\"Unauthorized\"}");
            return false;
        }

        return true;
    }
}

策略 3:使用 @CrossOrigin 进行细粒度控制

对于不需要全局跨域,或者特定接口需要特殊跨域规则的场景,可以直接在 Controller 类或方法上使用 @CrossOrigin 注解。

@RestController
@RequestMapping("/secure-api")
@CrossOrigin(origins = "https://trusted-domain.com", allowCredentials = "true")
public class SecureController {

    @GetMapping("/data")
    public ResponseEntity<String> getSecureData() {
        return ResponseEntity.ok("Secure Data");
    }
}

四、兼容凭证(Cookie)与通配符 Origin 的现代方案

在早期的 Spring 版本中,如果设置了 allowCredentials(true),则不允许将 allowedOrigins 设置为 "*",这会引发配置冲突。从 Spring Framework 5.3(对应 Spring Boot 2.4+)开始,引入了 allowedOriginPatterns 属性来完美解决这一问题。

@Bean
public CorsConfigurationSource advancedCorsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    
    // 使用 Pattern 支持通配符,同时兼容 Credentials
    configuration.addAllowedOriginPattern("*"); 
    
    configuration.setAllowCredentials(true);
    configuration.addAllowedHeader("*");
    configuration.addAllowedMethod("*");
    configuration.addExposedHeader(HttpHeaders.SET_COOKIE);
    configuration.setMaxAge(86400L); // 缓存预检请求结果 24 小时

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}

这种配置方式不仅避免了旧版本中的启动异常,还能灵活匹配复杂的子域名跨域需求(例如 *.example.com),是目前 Spring Boot 项目中处理全局跨域的最佳实践。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

linux screen 用法详情 (nohup 的替代方案)

一、screen 是什么?能干嘛?screen 是一个终端复用器,可以:在一个 SSH 会话中开多个“虚拟终端”SSH 断线后,程序仍然在后台运行随时重新连接到原来的会话特别适合:nohup 的替代方案跑脚本 / 爬虫 / 训练模型运维、远程开发二、安装 screen# CentOS / Rocky / Almayum install -y screen# Debian / Ubuntuapt i...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。