瞧瞧别人家的跨域方案,那叫一个优雅!

向量数据库大模型云通信

大家好,我是苏三,又跟大家见面了。

1 什么是跨域问题?

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

picture.image

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

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

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

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

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

举个栗子🌰:


        
          
// 前端代码(http://localhost:8080fetch('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请求,测试没问题,但浏览器报错,别怀疑人生,这可能是前端的锅!

最后欢迎 加入苏三的星球 ,你将获得:苏三AI项目、 商城微服务实战、秒杀系统实战 、 商城系统实战、秒杀系统实战、代码生成工具、系统设计、性能优化、技术选型、底层原理、Spring源码解读、工作经验分享、痛点问题、面试八股文等多个优质专栏。

还有1V1答疑、修改简历、职业规划、送书活动、技术交流。

picture.image

目前星球已经更新了5200+篇优质内容,还在持续爆肝中.....

星球已经被官方推荐了3次,收到了小伙伴们的一致好评。戳我加入学习,已有1600+小伙伴加入学习。

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
vivo 容器化平台架构与核心能力建设实践
为了实现规模化降本提效的目标,vivo 确定了基于云原生理念构建容器化生态的目标。在容器化生态发展过程中,平台架构不断演进,并针对业务的痛点和诉求,持续完善容器化能力矩阵。本次演讲将会介绍 vivo 容器化平台及主要子系统的架构设计,并分享重点建设的容器化核心能力。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论