回答
跨域问题是一个前端和后端的通信问题,发生在浏览器窒息感同源策略时,限制了前端网页向其域名、协议、端口不同的服务器发生请求。比如前端的页面运行在 http://localhost:3000
,而后端服务运行在 http://localhost:8080
,这种情况下的请求就会触发跨域问题。
Spring Boot 提供了三种方式来解决跨域问题:
- 使用 @CrossOrigin 注解:适用于单个控制器或方法,指定允许跨域的来源。
- 全局配置 CORS:通过实现
WebMvcConfigurer
接口的addCorsMappings
方法,进行全局跨域配置。 - 配置过滤器:自定义一个跨域过滤器,添加所需的 CORS 头。
详解
什么是跨域问题
跨域是指浏览器的同源策略限制了网页向其他域发送请求的行为。同源策略要求协议、域名、端口号必须一致。例如:
http://skjava.com:80
和https://``skjava``.com:80
不同源(协议不同)。http://``skjava``.com:80
和http://``skjava``.com:8080
不同源(端口不同)。http://``skjava``.com
和http://api.``skjava``.com
不同源(域名不同)
当浏览器检测到跨域请求时,会自动触发 CORS
(跨域资源共享,Cross-Origin Resource Sharing)检查。如果服务器没有正确设置 CORS
相关的响应头,浏览器会拦截请求,并报出跨域错误。
CORS 机制的工作方式
CORS
的核心在于浏览器与服务器之间通过 HTTP 头进行协商。具体过程如下:
简单请求
简单请求是指满足以下条件的 HTTP 请求:
- 使用方法为
GET
、POST
或HEAD
。 - 请求头只能包含以下字段:
Accept
、Accept-Language
、Content-Language
、Content-Type
(仅限值为application/x-www-form-urlencoded
、multipart/form-data
或text/plain
)。
对于简单请求,浏览器直接发出请求,但需要服务器在响应头中返回:
Access-Control-Allow-Origin: http://localhost:3000
预检请求
当请求不满足简单请求的条件(如使用了复杂的请求头或方法),浏览器会先发送一个 OPTIONS 请求进行预检,确认服务器是否允许跨域。例如:
浏览器发出的预检请求:
OPTIONS /api/data HTTP/1.1
Origin: http://localhost:3000
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type
服务器返回的预检响应:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Credentials: true
Spring Boot 如何解决跨域问题
使用 @CrossOrigin 注解
使用 @CrossOrigin
来标注某些方法允许跨域访问。例如:
@RestController
@RequestMapping("/skjava")
public class MyController {
@GetMapping("/getSkjavaInfo")
@CrossOrigin(origins = "http://localhost:3000") // 指定允许跨域的来源
public String getSkjavaInfo() {
return "Hello, Cross-Origin!";
}
}
origins
参数用于指定允许的来源,可以是具体的域名(如 http://skjava.com:80
,表示只允许指定域名跨域)或通配符(*
,表示所有域名都可以跨域访问)。但是它只适用于那些特定的接口部分放开跨域。
全局配置 CORS
有些情况我们需要全局允许跨域,这个时候我们就需要全局配置跨域了,如下:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 匹配所有请求路径
.allowedOrigins("http://localhost:3000") // 允许的来源
.allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的请求方法
.allowedHeaders("*") // 允许的请求头
.allowCredentials(true); // 允许发送 Cookie
}
}
配置过滤器
在更加复杂的场景下,我们可能需要对请求头、响应头等进行更加细粒度的控制,此时我们就可以创建一个过滤器来实现:
@Component
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(request, response);
}
}
这种方式自由度比较高,但是实现难度比较大,复杂性高,比较适合那些复杂的需求场景。
浏览器的 CORS 是一种客户端安全保护机制,在实际开发中我们应该避免全局放开跨域,防止安全问题。
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。