在现代 Web 开发中,前后端分离已成为主流架构。然而,这种架构在带来开发便利的同时,也引发了跨域资源共享(CORS)问题。本文将深入探讨同源策略、跨域的概念,以及在 Java 项目中解决 CORS 问题的常见方法。
参考文献
- JAVA | Java 解决跨域问题 花式解决跨域问题
- 九种常见的跨域解决方案(详解)
- 前后端分离后,Java Web 开发如何解决跨域问题
- Java 实现后端跨域的常见解决方式
- java 解决 CORS 跨域问题【总结】
- Spring Boot 解决跨域问题的 3 种方案!
1.同源策略
1.1 同源策略的概念
同源策略(Same-Origin Policy)是浏览器的一项重要安全机制,规定只有当两个页面的 协议、域名 和 端口 均相同时,页面之间才能互相访问资源。其主要目的是防止恶意网站通过脚本窃取用户在其他网站的敏感信息,保护用户数据的安全性和隐私性。
1.2 同源策略的示例
示例 | 说明 | 是否同源 |
---|---|---|
http://example.com/app1 与 http://example.com/app2 | 协议、域名、端口均相同 | ✅ 是同源 |
https://secure.example.com 与 https://secure.example.com/login | 协议、域名、端口均相同 | ✅ 是同源 |
http://example.com 与 https://example.com | 协议不同 | ❌ 非同源 |
http://example.com 与 http://sub.example.com | 域名不同 | ❌ 非同源 |
http://example.com:80 与 http://example.com:8080 | 端口不同 | ❌ 非同源 |
2. 跨域
2.1 CORS 的概念
跨域是指在浏览器中,当前网页尝试请求不同源(协议、域名、端口任一不同)的资源时,受到同源策略的限制,导致请求被阻止的现象。这在前后端分离、微服务架构等场景下尤为常见。
2.2 CORS 的分类
根据请求的复杂程度,CORS 可分为两类:
类型 | 描述 |
---|---|
简单请求 | 满足以下条件: 1. 使用 GET、POST、HEAD 方法之一。 2. 请求头包含以下字段:Accept、Accept-Language、Content-Language。 |
非简单请求 | 不满足简单请求条件,浏览器会发送 OPTIONS 预检请求,确认服务器是否允许该请求。 |
3. Java 代码解决 CORS 问题的方法
在 Java 项目中,常用的解决 CORS 问题的方法包括:
3.1 使用 FilterRegistrationBean
通过 Spring Boot 提供的 FilterRegistrationBean 注册过滤器:
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
/**
* 跨域配置过滤器,解决CORS跨域问题。
*
* @author wangguangwu
*/
@Configuration
public class CorsFilterConfig {
private static final String ALLOWED_METHODS = "GET, POST, PUT, DELETE, OPTIONS";
private static final String ALLOWED_HEADERS = "Content-Type, Authorization";
private static final String MAX_AGE = "3600";
@Bean
public FilterRegistrationBean<Filter> corsFilter() {
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(this::doCorsFilter);
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(1);
return registrationBean;
}
private void doCorsFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String origin = request.getHeader("Origin");
if (origin != null && !origin.isEmpty()) {
response.setHeader("Access-Control-Allow-Origin", origin);
}
response.setHeader("Access-Control-Allow-Methods", ALLOWED_METHODS);
response.setHeader("Access-Control-Allow-Headers", ALLOWED_HEADERS);
response.setHeader("Access-Control-Max-Age", MAX_AGE);
response.setHeader("Access-Control-Allow-Credentials", "true");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
return;
}
chain.doFilter(req, res);
}
}
3.2 实现 WebMvcConfigurer
通过实现 Spring 提供的 WebMvcConfigurer 接口实现全局跨域配置:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
- 全局跨域配置类
- <p>
- 通过实现 {@link WebMvcConfigurer} 接口,为整个应用提供统一的跨域支持。
- 适用于前后端分离的项目。
*
- @author wangguangwu
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
/**
- 配置跨域映射规则。
*
- @param registry 跨域注册器,用于定义跨域规则。
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
// 匹配所有路径
registry.addMapping("/**")
// 允许跨域的源,可根据需求替换
.allowedOrigins(
"http://localhost:5175"
)
// 允许的 HTTP 方法
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
// 允许的请求头,* 表示支持所有头
.allowedHeaders("*")
// 允许发送 Cookie 和凭据
.allowCredentials(true)
// 设置预检请求的有效时间,单位为秒
.maxAge(3600);
}
}
3.3 使用 @CrossOrgin
注解
通过 @CrossOrigin 注解为控制器或方法级别启用跨域支持:
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 局部跨域配置
*
* @author wangguangwu
*/
@RestController
public class UserController {
@CrossOrigin(origins = "http://localhost:3000")
@GetMapping("/user")
public String getUser() {
return "User information";
}
}
4. 总结
上述方法通过设置 Access-Control-Allow-Origin 等响应头,灵活解决跨域问题。不同场景下可以选择:
- 全局跨域配置:FilterRegistrationBean 或 WebMvcConfigurer。
- 局部跨域配置:@CrossOrigin 注解。
通过合理配置,可以有效解决 Java 项目中的跨域问题,确保前后端分离架构的通信正常。