您好,登录后才能下订单哦!
# SpringBoot怎么解决跨域
## 一、什么是跨域问题
### 1.1 跨域的定义
跨域(Cross-Origin)是指浏览器出于安全考虑,限制网页脚本向不同源(协议+域名+端口)的服务发起HTTP请求。这是浏览器的同源策略(Same-Origin Policy)导致的限制。
### 1.2 同源策略详解
同源策略要求以下三个必须相同:
- 协议(http/https)
- 域名(www.example.com)
- 端口(80/443)
示例对比:
| 当前URL | 请求URL | 是否同源 | 原因 |
|---------|---------|---------|------|
| http://a.com | http://a.com/api | 是 | 仅路径不同 |
| https://a.com | http://a.com | 否 | 协议不同 |
| http://a.com:8080 | http://a.com | 否 | 端口不同 |
### 1.3 跨域的常见场景
1. 前后端分离开发时,前端域名与API服务域名不同
2. 调用第三方API服务
3. 微服务架构中服务间调用
## 二、SpringBoot解决跨域的5种方案
### 2.1 使用@CrossOrigin注解
#### 2.1.1 方法级配置
```java
@RestController
@RequestMapping("/api")
public class MyController {
@CrossOrigin
@GetMapping("/users")
public List<User> getUsers() {
// ...
}
}
@CrossOrigin(origins = "http://localhost:3000",
maxAge = 3600,
allowedHeaders = {"Content-Type","Authorization"})
@RestController
@RequestMapping("/api")
public class MyController {
// 所有方法都支持跨域
}
参数 | 说明 | 示例值 |
---|---|---|
origins | 允许的源 | “http://a.com” |
methods | 允许的HTTP方法 | {RequestMethod.GET, RequestMethod.POST} |
allowedHeaders | 允许的请求头 | {“Content-Type”,“X-Token”} |
exposedHeaders | 暴露的响应头 | {“X-Custom-Header”} |
maxAge | 预检请求缓存时间(秒) | 1800 |
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://localhost:3000");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.setMaxAge(3600L);
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://localhost:8080;
# CORS headers
add_header 'Access-Control-Allow-Origin' '$http_origin' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
# 处理OPTIONS预检请求
if ($request_method = 'OPTIONS') {
return 204;
}
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
.authorizeRequests()
// 其他安全配置...
.anyRequest().authenticated();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
@Component
public class SimpleCORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
chain.doFilter(req, res);
}
// 其他Filter方法...
}
当请求满足以下条件时,浏览器会先发送OPTIONS预检请求: 1. 使用PUT、DELETE等非简单方法 2. 设置了自定义请求头 3. Content-Type不是以下三种: - text/plain - multipart/form-data - application/x-www-form-urlencoded
响应头 | 说明 | 示例值 |
---|---|---|
Access-Control-Allow-Origin | 允许的源 | * 或 http://a.com |
Access-Control-Allow-Methods | 允许的方法 | GET, POST, OPTIONS |
Access-Control-Allow-Headers | 允许的请求头 | Content-Type, X-Token |
Access-Control-Expose-Headers | 暴露的响应头 | X-Custom-Header |
Access-Control-Max-Age | 预检请求缓存时间 | 86400 |
Access-Control-Allow-Credentials | 是否允许发送cookie | true |
当需要发送cookie或认证信息时:
1. 前端需要设置withCredentials: true
2. 服务端必须:
- 指定具体域名(不能是*)
- 设置Access-Control-Allow-Credentials: true
axios.get('http://api.example.com/data', {
withCredentials: true
});
方案 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
@CrossOrigin | 简单项目/特定接口 | 配置简单 | 不适合复杂配置 |
全局CORS配置 | 大多数SpringBoot项目 | 统一管理 | 需要理解配置项 |
Nginx代理 | 生产环境部署 | 性能好,统一入口 | 需要运维知识 |
Spring Security | 已使用Security的项目 | 与认证集成 | 配置较复杂 |
自定义Filter | 需要高度定制 | 完全控制流程 | 需要手动处理细节 |
allowedOrigins("*")
:应该明确指定允许的域名allowedMethods("*")
SpringBoot提供了多种灵活的跨域解决方案,开发者可以根据项目需求选择合适的方式。理解CORS的工作原理和浏览器行为对于正确配置至关重要。在安全性和便利性之间需要做好平衡,特别是在生产环境中要谨慎配置。
随着前端技术的发展,跨域问题会持续存在,但通过合理的架构设计(如API网关、微服务聚合层)可以减少前端直接面对跨域问题的机会。掌握这些解决方案将帮助开发者构建更健壮的Web应用系统。 “`
这篇文章共计约3900字,包含了: 1. 跨域问题的原理说明 2. 5种解决方案及代码示例 3. 技术细节和最佳实践 4. 方案对比和选型建议 5. 常见问题排查方法
格式采用标准的Markdown语法,包含代码块、表格、列表等元素,可以直接用于技术文档发布。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。