开发者

前后端解决跨域问题的6种方案分享

目录
  • 1 什么是跨域问题
  • 2 解决跨域问题的方案
    • 2.1 CORS(跨域资源共享)
    • 2.2 jsONP
    • 2.3 NbZVzNiUginx反向代理
    • 2.4 网关层统一处理
    • 2.5 WebSocket
    • 2.6 PostMessage
  • 总结

    1 什么是跨域问题

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

    前后端解决跨域问题的6种方案分享

    其实这事儿得怪浏览器的“同源策略”(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);
        }
    }

    关键响应头:

    Access-Control-Allow-Origin: http://localhost:8080(允许的源)

    Access-Control-Allow-Methods: GET,POST(允许的方法)

    Access-Control-Allow-Credentials: true(允许带Cookie)

    注意坑点:

    如果用了allowCredentials(true),allowedOrigins不能为*(必须明确指定域名)。

    复杂请求(比如Content-Type是application/json)会先发一个OPTIONS预检请求,记得处理!

    2.2 JSONP

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

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

    前端代码:

    function handleUserData(data) http://www.devze.com{
        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 callbackandroid + "(" + 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 Gatewaphpy、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请求,测试没问题,但浏览器报错,别怀疑人生,这可能是前端的锅!

    以上就是前后端解决跨域问题的6种方案分享的详细内容,更多关于前后端解决跨域问题的资料请关注编程客栈(www.devze.com)其它相关文章!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜