SpringBoot:CORS是什么?SpringBoot如何解决跨域问题?

2024-06-13 03:52

本文主要是介绍SpringBoot:CORS是什么?SpringBoot如何解决跨域问题?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、简介

  跨域资源共享(CORS, Cross-Origin Resource Sharing)是一个W3C规范,它定义了一种浏览器和服务器交互的方式来确定是否允许跨源请求。当一个资源(如HTML页面、JavaScript文件、图片等)从一个源(origin)被请求到另一个源时,就会发生跨域请求。出于安全原因,浏览器会限制跨域请求,但CORS规范提供了一种机制,允许服务器明确指示哪些源可以访问其资源。

二、什么情况下需要CORS?

跨域数据访问
  当一个Web应用需要从另一个域(包括协议、域名、端口三者之一不相同)加载资源时,就会触发跨域问题。

  例如,一个位于https://test.com的网页试图访问http://api.anotherdomain.com提供的API数据,由于两个URL的域名不同,浏览器会阻止这种跨域请求,以保护用户数据不被恶意脚本获取。此时,就需要CORS来允许这种跨域访问。

图片、字体和媒体资源跨域引用
  在网页开发中,经常会引用到图片、字体和媒体资源,这些资源可能存放在不同的域名下。由于浏览器的同源策略,这些跨域资源的引用可能会被阻止。CORS允许服务器指定哪些域可以访问其资源,从而允许网页跨域引用这些资源。

三、CORS请求示例

1. 简单请求(Simple Request)

请求头示例:

  当浏览器发现是一个简单请求时(例如,使用GET、HEAD或POST方法,并且请求头中只包含简单的字段,如Accept、Accept-Language、Content-Language、Content-Type且Content-Type的值只能是text/plain、multipart/form-data或application/x-www-form-urlencoded),它会自动在请求头中加上Origin字段,告诉服务器这个请求来自哪个源(请求协议+域名+端口)。

GET /cors HTTP/1.1  
Origin: http://api.bob.com  
Host: api.alice.com  
Accept-Language: en-US  
Connection: keep-alive  
User-Agent: Mozilla/5.0...

响应头示例:

  服务器在收到请求后,会检查Origin字段。如果字段值在服务器的许可范围内,服务器会返回一个带有CORS相关响应头的HTTP响应。

HTTP/1.1 200 OK  
Access-Control-Allow-Origin: http://api.bob.com  
Access-Control-Allow-Credentials: true  
Content-Type: text/html; charset=utf-8  

2. 非简单请求(Not-So-Simple Request)

  对于非简单请求(例如,使用PUT、DELETE方法,或使用自定义的请求头),浏览器的CORS请求分为两步:

第一步:预检请求(Preflight Request)

  浏览器首先会发送一个OPTIONS请求到服务器,询问是否允许跨域请求。这个请求会包含一些额外的头部字段,如Access-Control-Request-Method和Access-Control-Request-Headers。

OPTIONS /cors HTTP/1.1  
Origin: http://api.bob.com  
Access-Control-Request-Method: PUT  
Access-Control-Request-Headers: X-Custom-Header  

第二步:实际请求(Actual Request)

  如果服务器在预检请求的响应中允许了跨域请求,浏览器才会发送实际的请求。

PUT /cors HTTP/1.1  
Origin: http://api.bob.com  
X-Custom-Header: foobar  
...

预检请求的响应头示例

  服务器在收到预检请求后,会检查请求头中的字段,并决定是否允许跨域请求。如果允许,服务器会返回一个带有CORS相关响应头的HTTP响应。

HTTP/1.1 200 OK  
Access-Control-Allow-Origin: http://api.bob.com  
Access-Control-Allow-Methods: PUT, DELETE  
Access-Control-Allow-Headers: X-Custom-Header  
Access-Control-Max-Age: 86400  

简单请求:浏览器直接发送带有Origin字段的请求,服务器通过响应头中的CORS相关字段来决定是否允许跨域访问。

非简单请求:浏览器首先发送一个OPTIONS预检请求,询问服务器是否允许跨域请求。如果允许,浏览器才会发送实际的请求。服务器通过预检请求的响应头中的CORS相关字段来决定是否允许跨域请求。

四、什么是预检请求

  CORS的预检请求是浏览器在发送某些跨域请求之前的一个安全机制。它通过向目标服务器发送一个额外的OPTIONS请求来检查服务器是否允许该跨域请求。如果服务器在响应中允许了跨域请求,那么浏览器才会发送实际的跨域请求。这个机制有助于保护用户数据不被恶意脚本获取,同时允许合法的跨域请求得以执行。

触发条件

  1.请求方法不是GET、HEAD或POST:当浏览器尝试使用除GET、HEAD或POST之外的方法(如PUT、DELETE等)发送跨域请求时,会触发预检请求。

  2.请求头中包含自定义头部字段:如果跨域请求中包含了自定义的HTTP头部字段(如X-Custom-Header),并且这些字段的值不在简单的头部字段列表中,那么也会触发预检请求。

  3.发送了application/json格式的数据:当浏览器向服务器发送包含Content-Type: application/json的请求头时,也会触发预检请求。

预检请求的过程

  浏览器发送OPTIONS请求:浏览器首先会发送一个HTTP OPTIONS请求到目标服务器,这个请求不包含任何实际的数据,而是包含了一些CORS相关的请求头,如Access-Control-Request-Method(指定实际请求的方法)和Access-Control-Request-Headers(指定实际请求中包含的自定义头部字段)。

OPTIONS /cors HTTP/1.1  
Origin: http://api.bob.com  
Access-Control-Request-Method: PUT  
Access-Control-Request-Headers: X-Custom-Header

  服务器响应OPTIONS请求:服务器在收到OPTIONS请求后,会检查请求头中的字段,并决定是否允许跨域请求。如果允许,服务器会返回一个带有CORS相关响应头的HTTP响应。

HTTP/1.1 200 OK  
Access-Control-Allow-Origin: http://api.bob.com  
Access-Control-Allow-Methods: PUT, DELETE  
Access-Control-Allow-Headers: X-Custom-Header  
Access-Control-Max-Age: 86400  

  浏览器发送实际请求:如果服务器在预检请求的响应中允许了跨域请求,那么浏览器会发送实际的跨域请求。这个请求会包含实际的数据和所有必要的请求头。

五、CORS中常用的HTTP响应头

CORS主要通过在HTTP响应头中添加特定的字段来控制跨域访问。以下是CORS中常用的HTTP响应头:

Access-Control-Allow-Origin
这个响应头指定了哪些源(域名、协议和端口)有权限访问该资源。
如果要允许所有源,可以设置为*(但请注意,这可能会带来安全风险,特别是当涉及到敏感数据时)。
示例:Access-Control-Allow-Origin: https://test.com

Access-Control-Allow-Methods
这个响应头指定了服务器支持的跨域请求的方法(HTTP方法,如GET、POST、PUT、DELETE等)。
示例:Access-Control-Allow-Methods: GET, POST, OPTIONS

Access-Control-Allow-Headers
这个响应头指定了服务器允许在跨域请求中使用的头部字段。
示例:Access-Control-Allow-Headers: Content-Type, X-Requested-With

Access-Control-Allow-Credentials
这个响应头是一个布尔值,指定是否允许在跨域请求中包含用户凭据(如cookies、HTTP认证或客户端SSL证明)。
如果设置为true,浏览器会向服务器发送凭据。但请注意,Access-Control-Allow-Origin不能设置为*,必须明确指定允许的源。
示例:Access-Control-Allow-Credentials: true

Access-Control-Max-Age
这个响应头指定了预检请求(preflight request,即OPTIONS请求)的结果可以被缓存多久(以秒为单位)。
浏览器会在缓存期内跳过预检请求,从而提高性能。
示例:Access-Control-Max-Age: 86400(一天)

Access-Control-Expose-Headers
这个响应头指定了哪些头部字段应该被包含在跨域请求的响应中,并可以通过getResponseHeader()方法访问。
默认情况下,跨域请求只能访问简单的响应头(如Cache-Control、Content-Language、Content-Type、Expires、Last-Modified和Pragma)。
示例:Access-Control-Expose-Headers: X-My-Custom-Header

六、SpringBoot中如何解决跨域问题

1.使用@CrossOrigin注解:

  你可以在控制器类或方法上使用@CrossOrigin注解来允许跨域请求。

@RestController  
@RequestMapping("/test")  
@CrossOrigin(origins = "http://test.com") // 允许来自http://test.com的跨域请求  
public class MyController {  // ...  
}

或者只在需要的方法上使用:

@GetMapping("/data")  
@CrossOrigin(origins = "http://test.com")  
public ResponseEntity<String> getData() {  // ...  
}

2.全局配置

  配置WebMvcConfigurer你可以实现WebMvcConfigurer接口并重写addCorsMappings方法来全局配置CORS。

@Configuration  
public class WebConfig implements WebMvcConfigurer {  @Override  public void addCorsMappings(CorsRegistry registry) {  registry.addMapping("/**") // 允许所有路径的跨域请求  .allowedOrigins("http://test.com") // 允许来自http://test.com的跨域请求  .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的方法  .allowedHeaders("*") // 允许的头部  .allowCredentials(true) // 是否允许发送cookies  .maxAge(3600); // 预检请求的缓存时间(秒)  }  
}

3.使用过滤器(Filter)

  你也可以通过自定义Filter来处理CORS请求。这通常在你需要更复杂的CORS逻辑时使用。

@Component  
public class CorsFilter implements Filter {  @Override  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)  throws IOException, ServletException {  HttpServletResponse response = (HttpServletResponse) res;  response.setHeader("Access-Control-Allow-Origin", "http://test.com");  response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");  response.setHeader("Access-Control-Allow-Headers", "*");  response.setHeader("Access-Control-Allow-Credentials", "true");  chain.doFilter(req, res);  }  // ... 其他方法  
}
注意:如果你使用@Component注解,则Spring Boot会自动注册这个过滤器。

以上是跨域问题的详细介绍,以及SpringBoot中如何解决跨域问题相关代码示例。

这篇关于SpringBoot:CORS是什么?SpringBoot如何解决跨域问题?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1056202

相关文章

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

MyBatis模糊查询报错:ParserException: not supported.pos 问题解决

《MyBatis模糊查询报错:ParserException:notsupported.pos问题解决》本文主要介绍了MyBatis模糊查询报错:ParserException:notsuppo... 目录问题描述问题根源错误SQL解析逻辑深层原因分析三种解决方案方案一:使用CONCAT函数(推荐)方案二:

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll

Redis 热 key 和大 key 问题小结

《Redis热key和大key问题小结》:本文主要介绍Redis热key和大key问题小结,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、什么是 Redis 热 key?热 key(Hot Key)定义: 热 key 常见表现:热 key 的风险:二、

Java中的工具类命名方法

《Java中的工具类命名方法》:本文主要介绍Java中的工具类究竟如何命名,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Java中的工具类究竟如何命名?先来几个例子几种命名方式的比较到底如何命名 ?总结Java中的工具类究竟如何命名?先来几个例子JD