Spring学习笔记_46——@InitBinder
Spring学习笔记_47——@RequestAttribute
Spring学习笔记_49——@ResponseBody
@CrossOrigin
文章目录
- @CrossOrigin
- 1. 介绍
- 2. 场景
- 3. 源码
- 4. Demo
- 4.1 的那个控制器或方法的CORS配置
- 4.2 全局CORS配置
- 5. 注意事项
- 6. 补充
- 同源策略(Same-Origin Policy)
- 跨域问题的产生
- 跨域请求的类型
- 解决跨域问题的方法
1. 介绍
@CrossOrigin是Spring Framework中的一个注解,用于处理跨域资源共享(Cross-Origin Resource Sharing, CORS)问题。
2. 场景
@CrossOrigin注解的使用场景主要包括以下几种情况:
- Web组件或插件:如果你开发了一个Web组件或插件,它需要在其他网站上运行,并且需要与你的服务器通信,那么也需要处理跨域问题。
- 移动应用后端:移动应用通常与后端服务进行通信,如果移动应用和后端服务的域不同,也需要处理跨域请求。
- 本地开发:在本地开发环境中,开发者可能会使用不同的端口或本地服务器地址来模拟生产环境,这时本地开发服务器和前端应用之间也可能存在跨域问题。
3. 源码
/**
* @author Russell Allen
* @author Sebastien Deleuze
* @author Sam Brannen
* @author Ruslan Akhundov
* @since 4.2
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
// String数组类型的属性,用于指定可以跨域请求的源列表
@AliasFor("origins")
String[] value() default {};
// String数组类型的属性,作用与value属性相同
@AliasFor("value")
String[] origins() default {};
// 从Spring5.3版本开始提供
// String数组类型的属性,可以用于设置多个跨域匹配规则。
String[] originPatterns() default {};
// String数组类型的属性,用于指定请求时允许跨域请求的请求头列表
String[] allowedHeaders() default {};
// String数组类型的属性,表示响应头中允许访问的消息头
String[] exposedHeaders() default {};
// RequestMethod数组类型的属性,表示允许跨域请求的HTTP方法
// 默认情况下,允许请求的HTTP方法与@RequestMapping注解相同
RequestMethod[] methods() default {};
// String类型的属性,表示是否允许跨域发送Cookie信息
// 使用此属性时,必须在value属性或者origins属性中明确指定具体的访问域
String allowCredentials() default "";
// long类型的属性,表示预处理响应的最大缓存时间,单位为秒
// 默认值为1800秒,也就是30分钟
long maxAge() default -1;
}
4. Demo
4.1 的那个控制器或方法的CORS配置
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin(origins = "http://xopencode.com") // 允许指定域名的前端应用访问
public class OpenApiController {
@GetMapping("/api/data")
public Data getData() {
// 返回 API 数据
return newData(...);
}
}
4.2 全局CORS配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**") // 应用于 /api/ 下的所有路径
.allowedOrigins("http://xopencode.com", "https://anotherdomain.com") // 允许多个域名
.allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的方法
.allowedHeaders("*") // 允许的头
.allowCredentials(true) // 允许携带凭证
.maxAge(3600); // 预检请求的缓存时间
}
}
5. 注意事项
- 版本要求:@CrossOrigin注解在Spring Framework 4.2及以上版本才支持。
- 安全性:使用@CrossOrigin注解时,需要谨慎配置允许的源(origins)和方法(methods),以避免潜在的安全风险。特别是当allowCredentials设置为true时,允许携带凭证(如Cookies),这会增加Web应用程序受攻击的概率。
- 注解失效问题:在使用@CrossOrigin注解时,需要确保@RequestMapping注解中声明了请求方式,即需要增加method=RequestMethod.XXX。
6. 补充
跨域问题(Cross-Origin Resource Sharing, CORS)是Web开发中经常遇到的一个问题,它涉及到浏览器安全策略中的同源策略(Same-Origin Policy)。为了理解跨域问题,我们首先需要了解什么是“同源”。
同源策略(Same-Origin Policy)
同源策略是一种浏览器安全策略,用于限制一个域的文档或脚本如何与另一个域的资源进行交互。它规定,如果两个页面的协议、端口(如果有指定)和主机名都相同,则这两个页面具有相同的源,可以互相访问对方的资源。例如,http://example.com/app/page1.html
和 http://example.com/app/page2.html
是同源的,因为它们共享相同的协议(http)、主机名(example.com)和端口(默认端口80)。
跨域问题的产生
当浏览器中的一个页面尝试请求另一个不同源的资源时,就会产生跨域问题。例如,如果你的网页位于 http://example.com
,并且它尝试通过AJAX请求从 http://anotherdomain.com
获取数据,这时浏览器会阻止这个请求,因为它违反了同源策略。
跨域请求的类型
跨域请求通常分为两类:
- 简单请求:这类请求只使用GET、HEAD或POST方法,并且POST请求的内容类型只能是text/plain、multipart/form-data或application/x-www-form-urlencoded。此外,请求中不能包含自定义的HTTP头部。
- 预检请求:对于不满足简单请求条件的请求,浏览器会首先发送一个OPTIONS请求到目标服务器,以检查服务器是否允许跨域请求。这个OPTIONS请求被称为“预检请求”(preflight request)。如果服务器允许跨域请求,并且满足特定的条件(如允许的方法、头部等),那么浏览器才会发送实际的请求。
解决跨域问题的方法
- JSONP:这是一种早期的跨域解决方案,它利用的是
<script>
标签不受同源策略限制的特点。但是,JSONP只支持GET请求,并且存在安全风险(如XSS攻击)。 - CORS(Cross-Origin Resource Sharing):这是现代浏览器支持的跨域解决方案。CORS允许服务器通过设置特定的HTTP头部来指示浏览器允许跨域请求。这些头部包括
Access-Control-Allow-Origin
(允许跨域请求的源)、Access-Control-Allow-Methods
(允许的方法)等。 - 服务器代理:在某些情况下,如果无法修改目标服务器的CORS设置,可以通过设置一个中间服务器(代理服务器)来转发请求。这样,前端页面就可以向代理服务器发送请求,然后由代理服务器向目标服务器发送请求并返回结果。
- WebSocket:WebSocket是一种新的通信协议,它允许在用户的浏览器和服务器之间进行双向通信。WebSocket不受同源策略的限制,因此可以用于跨域通信。但是,WebSocket主要用于实时通信场景,而不是普通的HTTP请求。