导读:本期聚焦于深圳GEO公司创作的《Java后端如何解决跨域CORS问题?配置跨域访问策略的标准做法》,敬请观看详情。浏览器拦截了一个看似正常的请求,控制台报错信息里出现 CORS policy 字样,这种情况通常不是前端代码写错,而是服务端没有返回正确的跨域响应头。Java 后端要解决 CORS,需要先区分简单请求和预检请求:简单请求只需带 Origin 校验,预检请求还要处理 OPTIONS 方法。标准做法包括在 Spring Boot 中使用 @CrossOrigin 注解做局部放行、通过 WebMvcConfigurer 或 CorsFilter 做全局配置、以及结合 Spring Security 放行预检请求。配置时要明确 allowedOrigins、allowedMethods、allowedHeaders 和 allowCredentials 的取值,生产环境不建议同时使用 allowedOrigins 为星号并开启凭证。原生 Servlet 项目可以手写过滤器,Nginx 反向代理也能统一处理响应头。文章给出可直接运行的配置示例,并说明常见坑位和排查思路。

跨域问题几乎都出现在前后端分离架构里。浏览器出于同源策略限制,当一个请求从 http://localhost:5173 发到 http://localhost:8080 时,即使后端接口能正常处理并返回数据,浏览器也会把响应拦截下来,前端只能看到 CORS policy 报错。Java 后端要做的不是放开所有限制,而是按接口范围返回一组标准的跨域响应头,让浏览器完成校验。

Java后端如何解决跨域CORS问题?配置跨域访问策略的标准做法

接下来从请求类型、Spring Boot 配置、原生 Servlet、Nginx 以及排查方法几个角度展开。

一、先判断请求类型,才能知道要返回什么响应头

CORS 的表象是浏览器拦截响应,但服务端要做的事情并不是复杂地放行域名,而是根据请求类型补齐响应头。浏览器把跨域请求分成简单请求和需要预检的请求。

简单请求通常满足三个条件:请求方法为 GET、HEAD、POST;Content-Type 限于 application/x-www-form-urlencoded、multipart/form-data、text/plain;没有自定义请求头。这类请求不会先发 OPTIONS,浏览器直接携带 Origin 字段发起请求,服务器只要返回 Access-Control-Allow-Origin 即可。反之,一旦使用了 application/json、PUT、DELETE 或自定义头 Authorization,浏览器就会先发一个 OPTIONS 预检请求,询问服务器是否允许后续真实请求。

如果 Java 服务端只处理 GET/POST 业务路径,但没处理 OPTIONS,预检会直接失败,前端会看到 CORS policy: Response to preflight request doesn't pass access control check。这是 Java 后端最常见的跨域故障之一。

请求类型触发条件服务端处理
简单请求GET/HEAD/POST,Content-Type 受限,无自定义头返回 Access-Control-Allow-Origin
预检请求PUT、DELETE、application/json、自定义头先响应 OPTIONS,再放行真实请求

二、Spring Boot 的标准配置方式

Spring 框架提供了从注解到全局过滤器的多级支持,适合不同粒度。

2.1 使用 @CrossOrigin 注解做局部放行

如果只有少数接口需要跨域,可以直接在 Controller 或方法上加 @CrossOrigin。它的优点是粒度细,缺点是如果项目接口很多,到处加注解反而难维护。

@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:5173", maxAge = 3600)
public class UserController {

    @GetMapping("/info")
    public Map<String, Object> getInfo() {
        return Map.of("name", "测试用户");
    }
}

注解的 origins 参数可以传入多个来源,maxAge 用于设置预检结果缓存时间,单位是秒。allowCredentials 默认不开启,如果需要携带 Cookie,需要显式设置为 true,同时 origins 不能写成星号。

2.2 通过 WebMvcConfigurer 做全局配置

更常见的是把所有 /api/** 路径统一处理,集中配置 allowedOrigins、allowedMethods、allowedHeaders。可以考虑继承 WebMvcConfigurer 实现 addCorsMappings 方法。

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("http://localhost:5173", "https://app.ipipp.com")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

上面这个配置表示只有 /api 开头的接口会返回 CORS 头,来源列表明确写死,不向任意站点开放。allowedHeaders 使用星号表示接收所有请求头,生产环境如果对安全要求高,建议改成 Content-Type、Authorization 等实际使用字段。

2.3 使用 CorsFilter Bean 进行更早拦截

WebMvcConfigurer 是 MVC 层面的处理,如果项目里有非 MVC 的 Servlet 或自定义 Filter,更推荐用 CorsFilter Bean,它会在过滤链较早位置生效。

@Bean
public CorsFilter corsFilter() {
    CorsConfiguration config = new CorsConfiguration();
    config.addAllowedOrigin("http://localhost:5173");
    config.addAllowedMethod("*");
    config.addAllowedHeader("*");
    config.setAllowCredentials(true);
    config.setMaxAge(3600L);

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/api/**", config);
    return new CorsFilter(source);
}

CorsFilter 与 WebMvcConfigurer 二选一即可,同时配置可能造成响应头重复。如果项目使用 Spring Security,单独配置 WebMvcConfigurer 通常不够,因为 OPTIONS 请求可能在到达 MVC 之前就被安全过滤链拦截。

2.4 结合 Spring Security 放行预检请求

Spring Security 会拦截所有请求,包括预检 OPTIONS。需要在 SecurityFilterChain 里启用 CORS,并显式放行 OPTIONS。可以这样配置:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http.cors(Customizer.withDefaults())
        .authorizeHttpRequests(auth -> auth
            .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .anyRequest().authenticated()
        )
        .httpBasic(Customizer.withDefaults());
    return http.build();
}

这里 http.cors() 会尝试从 Spring 容器中读取 CorsConfigurationSource。如果已经定义了 CorsFilter 或 WebMvcConfigurer,Spring Security 会自动复用相应策略。如果不希望为预检请求单独写放行规则,也可以把 CORS 配置提升到安全链之前,但显式 permitAll 会更清晰直观。

三、原生 Servlet 与 Nginx 反向代理方案

不是所有 Java 项目都用 Spring Boot,原生 Servlet、老框架或前后端中间有 Nginx 的项目同样需要 CORS 支持。手写过滤器比较直接,适合不想引入额外依赖的场景。

@WebFilter("/*")
public class SimpleCorsFilter implements Filter {

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

        resp.setHeader("Access-Control-Allow-Origin", "http://localhost:5173");
        resp.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        resp.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
        resp.setHeader("Access-Control-Max-Age", "3600");

        if ("OPTIONS".equalsIgnoreCase(req.getMethod())) {
            resp.setStatus(HttpServletResponse.SC_OK);
            return;
        }

        chain.doFilter(request, response);
    }
}

如果应用前面挂了 Nginx,也可以在网关层统一添加响应头,这样 Java 服务自身不必改动。下面是一段常见的 Nginx 配置:

location /api/ {
    if ($request_method = OPTIONS) {
        add_header Access-Control-Allow-Origin http://localhost:5173;
        add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
        add_header Access-Control-Allow-Headers Content-Type,Authorization;
        add_header Access-Control-Max-Age 3600;
        return 204;
    }
    proxy_pass http://backend_server;
    add_header Access-Control-Allow-Origin http://localhost:5173;
    add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
    add_header Access-Control-Allow-Headers Content-Type,Authorization;
}

Nginx 的 if 指令只适合简单判断,如果有多环境、多域名来源,更稳妥的做法是用 map 动态设置 Access-Control-Allow-Origin。还需注意 add_header 的继承规则,如果内部 location 重新定义了 add_header,外层配置可能不生效。

四、配置中的常见坑与排查方法

CORS 配置看似简单,但实际排查时很容易被细节卡住。最常见的是配置了 allowCredentials(true),却把 allowedOrigins 写成星号。浏览器会认为这种组合不可信,CORS 校验仍然失败。Spring 5.3 之后提供了 allowedOriginPatterns,可以写成 allowedOriginPatterns("*") 配合 allowCredentials(true),框架会回显具体来源而不是返回星号。

另一个高频问题是只返回了 Access-Control-Allow-Origin,却漏掉 Access-Control-Allow-Headers。比如前端在请求头里带了 Authorization 或 X-Requested-With,预检请求会问服务器是否允许这些头。如果后端只配置了允许 Content-Type,预检同样失败。解决方法是先看浏览器 Network 面板里的 OPTIONS 请求,查看 Requested Headers 和响应头是否一一对应。

如果使用了自定义响应头,比如前端要读取 Content-Disposition 或 X-Total-Count,Java 后端还需要额外配置 Access-Control-Expose-Headers。否则浏览器虽然能收到响应,但 JavaScript 无法读取这些头的值,这种问题容易被误判为接口没返回数据。

排查时可以优先检查三件事:第一,请求是否为预检请求,OPTIONS 是否被安全框架拦截;第二,响应头里的 Origin 是否与当前页面来源完全一致,包括协议、域名、端口;第三,是否同时开启了凭证却没有使用具体来源。按照这个顺序检查,大多数 CORS 问题能在几分钟内定位。

Java跨域CORS配置跨域访问策略修改时间:2026-09-22 13:38:47

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0922/60500.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。