本文目录导读:

- 文章标题:Java跨域请求案例:从原理到彻底解决的完整指南(附实战代码)
- 目录导读
- 跨域问题的本质:为什么浏览器会拦截你的请求?
- Java后端常见跨域解决方案对比
- 案例一:Spring Boot + CORS全局配置(90%场景适用)
- 案例二:Nginx反向代理解决跨域(生产环境推荐)
- 案例三:JSONP与WebSocket的替代方案(特殊场景)
- 彻底解决跨域的4个关键检查点(附FAQ问答)
- 总结:哪种方案最适合你的项目?
Java跨域请求案例:从原理到彻底解决的完整指南(附实战代码)
目录导读
- 跨域问题的本质:为什么浏览器会拦截你的请求?
- Java后端常见跨域解决方案对比(含优缺点分析)
- Spring Boot + CORS全局配置(90%场景适用)
- Nginx反向代理解决跨域(生产环境推荐)
- JSONP与WebSocket的替代方案(特殊场景)
- 彻底解决跨域的4个关键检查点(附FAQ问答)
- 哪种方案最适合你的项目?
跨域问题的本质:为什么浏览器会拦截你的请求?
Q:什么是跨域?
A:当浏览器发起的请求协议、域名、端口三者之一与当前页面不同时,就会触发同源策略。
- 前端
http://localhost:8080请求后端http://api.example.com:8081→ 跨域 - 请求
https://www.a.com到http://www.a.com(协议不同)→ 跨域
Q:为什么要有同源策略?
A:防止恶意网站通过JavaScript读取用户在其他网站的数据(如CSRF攻击),但实际开发中,前端与后端分离部署(如前端部署在CDN,后端在独立服务器)是常态,因此必须解决跨域。
根本解决原则:要么让浏览器信任跨域请求(CORS),要么绕过浏览器限制(代理/JSONP)。
Java后端常见跨域解决方案对比
| 方案 | 适用场景 | 优点 | 缺点 | 安全性 |
|---|---|---|---|---|
| CORS(后端配置) | 单应用/可控域名 | 标准协议,浏览器原生支持 | 需要后端改动 | 需限制Origin |
| Nginx反向代理 | 生产环境/多服务 | 无需改后端代码,可做负载均衡 | 增加运维成本 | 可控 |
| JSONP | 老旧系统/GET请求 | 纯前端方案 | 仅支持GET,有安全风险 | 低 |
| WebSocket | 实时通信 | 无跨域限制 | 协议不同 | 需单独鉴权 |
核心结论:
- 对于99%的Java Web项目,CORS + Nginx组合是最优解。
- JSONP仅用于兼容不支持CORS的老系统。
案例一:Spring Boot + CORS全局配置(90%场景适用)
目标:允许前端 http://localhost:3000 的请求访问后端 http://localhost:8080 的所有接口。
步骤1:添加CORS配置类(推荐全局配置)
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 允许所有路径
.allowedOrigins("http://localhost:3000") // 允许的前端域名
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true) // 允许携带Cookie
.maxAge(3600); // 预检请求缓存时间(秒)
}
}
步骤2:处理预检请求(OPTIONS)
若前端使用复杂请求(如自定义Header、PUT/DELETE),浏览器会先发OPTIONS预检,Spring Boot会自动处理,但需确保Filter放行:
@Component
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
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");
if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
return;
}
chain.doFilter(req, res);
}
}
关键问题:
- 生产环境不要用
allowedOrigins("*"),否则任何网站都能调用你的API。 - 若前端携带Cookie(如Session认证),必须设置
allowCredentials(true)且allowedOrigins不能为 。
案例二:Nginx反向代理解决跨域(生产环境推荐)
原理:让前端请求同域名下的Nginx,由Nginx转发到后端Java服务,浏览器看到的是同一域名 → 无跨域。
Nginx配置示例:
server {
listen 80;
server_name api.example.com;
location /api/ {
proxy_pass http://localhost:8080/; # 后端Java服务
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 允许跨域(动态设置Origin)
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
add_header Access-Control-Allow-Credentials true;
# 处理预检请求
if ($request_method = 'OPTIONS') {
return 204;
}
}
}
优势:
- 后端Java代码无需修改。
- Nginx可做负载均衡、HTTPS终结、静态资源缓存。
常见坑:
- 如果后端接口路径是
/user/get,前端请求/api/user/get时,proxy_pass最后的 决定了路径是否覆盖(推荐加 去掉前缀)。
案例三:JSONP与WebSocket的替代方案(特殊场景)
Q:什么是JSONP?
A:利用 <script> 标签不受同源策略限制的特点,仅支持GET请求。
// 前端
$.ajax({
url: 'http://api.example.com/data?callback=handleData',
dataType: 'jsonp',
success: function(data) { console.log(data); }
});
致命缺点:
- 只能GET,无法POST/DELETE。
- 后端需支持callback参数(Spring Boot需自定义Controller)。
- 存在XSS漏洞(恶意callback可注入代码)。
WebSocket方案:
WebSocket协议不受同源策略限制,适合实时通信场景(如聊天、推送)。
// Java使用Spring WebSocket
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new MyHandler(), "/ws").setAllowedOrigins("*");
}
}
彻底解决跨域的4个关键检查点(附FAQ问答)
Q:配置了CORS还是报错,可能是什么原因?
- 检查预检请求:浏览器是否发了OPTIONS请求?后端是否返回了正确的Header?
- 检查Origin白名单:
allowedOrigins是否包含当前前端域名(含端口)? - 检查Credentials:如果前端
withCredentials: true,后端必须allowCredentials(true)且不能设Origin为。 - 检查Filter顺序:如果使用了Spring Security或其他Filter,需确保CORS Filter在它们之前执行(否则尚未添加Header就被拦截)。
Q:生产环境如何使用CORS?
- 动态读取配置文件中的
origin列表,而非硬编码。@Value("${cors.allowed-origins}") private String[] allowedOrigins; // registry.allowedOrigins(allowedOrigins);
Q:多域名如何配置?
registry.allowedOrigins("http://a.com", "https://b.com", "http://localhost:3000");
哪种方案最适合你的项目?
| 项目类型 | 推荐方案 | 理由 |
|---|---|---|
| 单体应用(前后端分离) | CORS全局配置 | 简单,无需额外组件 |
| 微服务架构 | Nginx反向代理 | 统一入口,方便管理鉴权与路由 |
| 老旧系统(IE兼容) | JSONP + CORS降级 | 兼顾兼容性与现代标准 |
| 实时通信/Web API | WebSocket + CORS | 无跨域限制,支持双向通信 |
最后提醒:
- *永远不要在生产环境使用CORS的 `` 通配符**,除非你的API是完全公开的。
- 跨域问题没有银弹,理解其原理比堆砌配置更重要,当问题出现时,从浏览器的Network面板查看响应Header,90%的bug都能通过对比预期Header定位。
你可以根据项目需求,选择最适合的方案,彻底告别跨域困扰。