CORS 全局配置

为什么需要 CORS

浏览器有同源策略:页面所在源(协议 + 域名 + 端口)与请求目标不同源时,响应会被浏览器拦截。前后端分离开发中,前端跑在 http://localhost:5173、后端跑在 http://localhost:8080,二者不同源,直接请求就会触发跨域问题。CORS(跨源资源共享)由服务端通过响应头声明「允许哪些来源访问」,浏览器据此放行。

简单请求与预检

  • 简单请求(如不带自定义头的 GET/POST 表单请求):浏览器直接带 Origin 头发送,服务端返回 Access-Control-Allow-Origin 即可;
  • 复杂请求(携带自定义头、application/json 的 PUT/DELETE 等):浏览器先发一个 OPTIONS 预检请求,确认许可后才发真实请求。

方式一:@CrossOrigin 注解

局部控制用注解,加在方法或类上(方法级优先于类级):

@CrossOrigin(origins = "https://example.com")
@RestController
public class UserController {
    // ...
}

不带参数的 @CrossOrigin 允许所有来源,开发期方便但生产慎用。本地联调时常写成 origins = "http://localhost:5173"

方式二:全局 WebMvcConfigurer(推荐)

跨域规则统一收敛到一处,通过 WebMvcConfigurer 配置:

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")                        // 这些路径参与 CORS
                .allowedOrigins("https://example.com")        // 允许的来源(生产不要写 *)
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")                          // 允许的请求头
                .allowCredentials(true)                       // 允许携带 Cookie
                .maxAge(3600);                                // 预检结果缓存 1 小时
    }
}

要点

  • allowCredentials(true)allowedOrigins("*") 不能同时用,浏览器会拒绝;需要把来源写具体。
  • 来源是动态或想用通配子域时,用 allowedOriginPatterns("https://*.example.com")(该 API 自 Spring 5.3 提供,4.x 沿用,具体以官方文档为准)。
  • 前端要读取自定义响应头时,用 exposedHeaders 暴露。
  • 校验失败会返回 403,浏览器控制台会提示具体被拒原因,按提示调整规则即可。

验证

# 观察响应头是否含 Access-Control-Allow-Origin
curl -i -H "Origin: https://example.com" http://localhost:8080/api/users

# 手动模拟预检
curl -i -X OPTIONS -H "Origin: https://example.com" \
     -H "Access-Control-Request-Method: POST" \
     http://localhost:8080/api/users

小结

跨域是「服务端许可 + 浏览器拦截」的机制。单体后端用 WebMvcConfigurer 全局配置最省心;若前端请求先经过 Nginx/网关转发,通常由网关层统一处理 CORS,后端保持默认即可,两者同时配置可能造成响应头重复。

笔记加载中…