⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 苏三说技术 「苏三」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

1 什么是跨域问题?

很多小伙伴第一次遇到跨域问题,大概率会一脸懵逼:“我后端接口明明通了,Postman也能调,为啥浏览器就报红字?”

其实这事儿得怪浏览器的“同源策略”(Same-Origin Policy)。

简单说,浏览器觉得“不同源的请求都是耍流氓”。

比如你的前端跑在http://localhost:8080。

而后端在https://api.xxx.com:8000。

只要协议、域名、端口任何一个不同,就会被浏览器直接掐断。

举个栗子🌰:

// 前端代码(http://localhost:8080)
fetch('http://api.xxx.com:8000/user')
.then(res => res.json())
.then(data => console.log(data));
// 浏览器控制台报错:
// Access to fetch from 'http://localhost:8080' has been blocked by CORS policy...

这时候,你就需要“跨域解决方案”来帮浏览器松绑了!

那么,如何解决跨域问题呢?

2 解决跨域问题的方案

2.1 CORS(跨域资源共享)

适用场景:前后端分离项目、接口需要兼容多种客户端。

CORS是W3C标准,后端只需在响应头里加几个字段,告诉浏览器“这个接口我允许谁访问”。

后端代码示例(Spring Boot版):

// 方法1:直接怼注解(适合单个接口)
@CrossOrigin(origins = "http://localhost:8080")
@GetMapping("/user")
public User getUser() { ... }

// 方法2:全局配置(一劳永逸)
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8080")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}

关键响应头:

注意坑点:

  • 如果用了allowCredentials(true),allowedOrigins不能为*(必须明确指定域名)。
  • 复杂请求(比如Content-Type是application/json)会先发一个OPTIONS预检请求,记得处理!

2.2 JSONP

适用场景:老项目兼容、只支持GET请求(比如调用第三方地图API)。

JSONP利用<script>标签没有跨域限制的特性,让后端返回一段JS代码。

前端代码:

function handleUserData(data) {
console.log("收到数据:", data);
}

// 动态创建script标签
const script = document.createElement('script');
script.src = 'http://api.xxx.com:8000/user?callback=handleUserData';
document.body.appendChild(script);

后端代码:

@GetMapping("/user")
public String jsonp(@RequestParam String callback) {
User user = new User("Tony", 30);
// 把数据包进回调函数里
return callback + "(" + new Gson().toJson(user) + ")";
}

输出结果:

handleUserData({"name":"Tony","age":30})

缺点:

  • 只支持GET(传参长度有限)。
  • 容易被XSS攻击(毕竟得信任第三方脚本)。

2.3 Nginx反向代理

适用场景:生产环境部署、微服务网关统一处理。

直接把跨域问题甩给Nginx,让浏览器以为所有请求都是同源的。

Nginx配置示例:

server {
listen 80;
server_name localhost;

location /api {
# 转发到真实后端
proxy_pass http://api.xxx.com:8000;
# 解决跨域
add_header 'Access-Control-Allow-Origin' 'http://localhost:8080';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type';
}
}

此时前端请求地址改成同源:

fetch('/api/user')  // 实际访问 http://localhost/api/user → 被Nginx转发

优点:

  • 前后端代码零侵入。
  • 能隐藏真实接口地址(安全加分)。

2.4 网关层统一处理

适用场景:Spring Cloud Gateway、Kong等API网关。

和Nginx思路类似,但更适合微服务场景,直接在网关层加CORS配置。

Spring Cloud Gateway配置:

spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowed-origins: "http://localhost:8080"
allowed-methods: "*"
allowed-headers: "*"
allow-credentials: true

2.5 WebSocket

适用场景:实时通信需求(聊天室、股票行情)。

WebSocket协议没有跨域限制(因为握手阶段走HTTP,后续升级为长连接)。

前端代码:

const socket = new WebSocket('ws://api.xxx.com:8000/ws');
socket.onmessage = (event) => {
console.log('收到消息:', event.data);
};

后端代码(Spring Boot):

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new MyWebSocketHandler(), "/ws");
}
}

2.6 PostMessage

适用场景:页面与iframe、弹窗之间的跨域通信。

通过window.postMessage实现不同窗口间的数据传递。

父页面(http://parent.com):

const childWindow = window.open('http://child.com');
childWindow.postMessage('我是你爹', 'http://child.com');

子页面(http://child.com):

window.addEventListener('message', (event) => {
if (event.origin !== 'http://parent.com') return; // 验证来源
console.log('收到爹的消息:', event.data);
});

总结

  • 简单粗暴:开发环境用CORS注解。
  • 生产环境:优先Nginx/网关统一处理,避免每个服务配一遍。
  • 老项目兼容:JSONP勉强能用,但别长期依赖。
  • 实时场景:直接上WebSocket,顺便解决通信问题。
  • 安全第一:Access-Control-Allow-Origin尽量别写*,白名单要用精确域名。

最后提醒温馨提醒一下:跨域问题本质是浏览器行为,和HTTP协议无关。

如果你用Postman,发送curl请求,测试没问题,但浏览器报错,别怀疑人生,这可能是前端的锅!

文章目录
  1. 1. 1 什么是跨域问题?
  2. 2. 2 解决跨域问题的方案
    1. 2.1. 2.1 CORS(跨域资源共享)
    2. 2.2. 2.2 JSONP
    3. 2.3. 2.3 Nginx反向代理
    4. 2.4. 2.4 网关层统一处理
    5. 2.5. 2.5 WebSocket
    6. 2.6. 2.6 PostMessage
  3. 3. 总结