当前位置: 首页 > backend >正文

Java注解篇:@CrossOrigin

前言

        在现代前后端分离的开发模式中,跨域请求(CORS)成为了不可避免的问题。浏览器的同源策略限制了不同源之间的请求交互,而 Spring Framework 为了解决这一问题,引入了 @CrossOrigin 注解。

    @CrossOrigin 是 Spring 4.2 引入的注解,允许我们在控制器或具体方法上启用跨域请求支持。它是实现 CORS 的便捷方式。

        本文将详细介绍 @CrossOrigin 的使用方法、注解参数、实际场景中的应用示例,以及其底层实现原理,帮助你全面理解并灵活使用该注解。


一、跨域基础知识

1. 什么是跨域

        跨域是指浏览器不能执行其他域下的脚本。一个域名下的网页去请求另一个域名下的资源,就构成了跨域。常见的跨域情况包括:

  • 协议不同(http vs https)

  • 域名不同(example.com vs api.example.com)

  • 端口不同(example.com:8080 vs example.com:8081)

2. 浏览器的同源策略

        同源策略(Same-Origin Policy)是浏览器的一个安全功能,它阻止一个源的 JavaScript 脚本去访问另一个源的内容。

3. CORS(跨源资源共享)

        CORS 是一种机制,它通过设置响应头来告诉浏览器:当前资源允许哪些域名访问,从而实现跨源访问。

常见的响应头包括:

  • Access-Control-Allow-Origin

  • Access-Control-Allow-Methods

  • Access-Control-Allow-Headers

  • Access-Control-Allow-Credentials


二、@CrossOrigin 注解使用

1. 基本使用

在控制器类上添加 @CrossOrigin

@CrossOrigin
@RestController
@RequestMapping("/api")
public class MyController {@GetMapping("/data")public String getData() {return "跨域数据";}
}

这将允许所有源对 /api/data 进行访问。

2. 作用范围

  • 类级别:对控制器中所有方法生效。

  • 方法级别:只对该方法生效,优先级高于类级别注解。

@RestController
@RequestMapping("/api")
public class MyController {@CrossOrigin(origins = "http://example.com")@GetMapping("/open")public String openAccess() {return "example.com 可访问";}@GetMapping("/restricted")public String restrictedAccess() {return "无跨域支持";}
}

3. 常用参数

属性描述
origins允许哪些来源访问,默认允许所有(*)
methods允许的 HTTP 方法(如 GET、POST)
allowedHeaders允许的请求头
exposedHeaders响应中暴露的头信息
allowCredentials是否允许携带 Cookie(默认为 false)
maxAge预检请求的缓存时间(单位:秒)
示例
@CrossOrigin(origins = "http://localhost:3000",methods = {RequestMethod.GET, RequestMethod.POST},allowedHeaders = {"Content-Type", "Authorization"},allowCredentials = "true",maxAge = 3600
)
@GetMapping("/secure-data")
public String secureData() {return "安全数据";
}

三、全局跨域配置

除了使用 @CrossOrigin 注解,我们也可以通过配置类来设置全局跨域策略:

@Configuration
public class CorsGlobalConfiguration implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("http://localhost:3000").allowedMethods("GET", "POST", "PUT", "DELETE").allowCredentials(true).maxAge(3600);}
}

全局配置可以替代注解形式,适用于统一配置策略的项目。


四、实现原理分析

1. 注解处理入口

    @CrossOrigin 是通过 Spring MVC 的处理器拦截器和过滤器链处理的,其底层依赖 CorsProcessor

        在 DispatcherServlet 初始化过程中,会将 HandlerMappingHandlerAdapter 组合成执行链,而跨域处理通过注册 CorsInterceptor 实现。

2. 核心组件

CorsFilter

    CorsFilter 是 Spring Web 提供的过滤器,用于处理所有请求的 CORS 校验。

public class CorsFilter extends OncePerRequestFilter {private final CorsConfigurationSource configSource;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {CorsConfiguration corsConfig = this.configSource.getCorsConfiguration(request);CorsProcessor processor = new DefaultCorsProcessor();processor.processRequest(corsConfig, request, response);}
}
DefaultCorsProcessor

        该类负责核心的跨域逻辑,包括解析请求头、设置响应头等。

public boolean processRequest(@Nullable CorsConfiguration config, HttpServletRequest request, HttpServletResponse response) {if (!this.isCorsRequest(request)) {return true;}// 校验 Origin、方法、头部等// 设置 Access-Control-* 响应头return true;
}

3. 与注解的结合

        当控制器或方法上有 @CrossOrigin 注解时,Spring 会自动解析注解配置并生成 CorsConfiguration 对象,注入到请求的上下文中,最终由 CorsFilter 应用。


五、注意事项

  1. allowCredentials = true 时,allowedOrigins 不能为 *,否则浏览器会拦截。

  2. 浏览器对 OPTIONS 请求是自动发出的“预检请求”,务必允许该方法。

  3. 不同浏览器对 CORS 处理略有差异,需进行充分测试。

  4. 建议跨域配置集中管理,避免分散在多个注解中。


六、常见问题与排查

问题 1:浏览器提示 CORS 错误

  • 检查响应中是否包含 Access-Control-Allow-Origin

  • 确认服务器是否允许对应的方法与头信息

  • 检查是否为预检请求被拒绝

问题 2:Cookie 无法携带

  • 需设置 allowCredentials = true

  • 客户端必须设置 xhr.withCredentials = true

  • 不能使用 * 通配源


七、总结

    @CrossOrigin 是一个简单但非常实用的注解,极大简化了跨域配置,特别适合前后端分离架构下的 API 接口服务。

        通过结合全局配置和方法级注解,我们可以灵活控制不同接口的访问策略,从而兼顾安全性与开发便利。掌握 @CrossOrigin 的使用和底层原理,是现代 Spring Boot 开发者的基本功之一。

http://www.xdnf.cn/news/7123.html

相关文章:

  • 鸿蒙AI开发:10-多模态大模型与原子化服务的集成
  • 大学之大:墨西哥国立自治大学2025.5.18
  • STM32项目实战:ADC采集
  • [原创工具] 小说写作软件
  • java springMVC+MyBatis项目1,服务端处理json,RequestBody注解,Form表单发送,JavaScript发送
  • 【量子计算与云架构】加密与算法革新展望
  • Python format()函数高级字符串格式化详解
  • LG P4722 LOJ 127 【模板】最大流 加强版 Solution
  • C语言练手磨时间
  • 编程速递:适用于 Delphi 12.3 的 FMX Linux 现已推出
  • C++面试2——C与C++的关系
  • 12.输出常量的两个小扩展
  • leetcode hot100刷题日记——2.字母异位词分组
  • 【第三篇】 SpringBoot项目中的属性配置
  • 中科院自动化研究所通用空中任务无人机!基于大模型的通用任务执行与自主飞行
  • Linux的内存泄漏问题及排查方法
  • 记录一次win11本地部署deepseek的过程
  • linux-----------------库制作与原理(下)
  • 宝塔9.6.0python项目程序运行卡住bug解决方案
  • mvc-ioc实现
  • 游戏引擎学习第291天:跳跃的怪物与占据的树木
  • Google aab包转成apk,并安装到手机设备中
  • 77.数据大小端赋值的差异与联系
  • 华为云Astro中各种变量与参数的区别与用法
  • C 语言字符串输入输出:scanf, gets, fgets 的选择与陷阱
  • Word文档图片和图表自动添加序号
  • 基于区块链技术的供应链溯源系统:重塑信任与透明度
  • 信奥赛-刷题笔记-栈篇-T2-P3056括号调整问题0518
  • Android日活(DAU)检测的四大实现方案详解
  • 代码随想录算法训练营 Day49 图论Ⅰ 深度优先与广度优先