简单谈谈跨域通信

背景

关于代码编辑器,如果我不存储数据,那么如何做到可以直接运行传入的代码呢?这就涉及到跨域通信了。下面我们一起来看看吧。

有哪些方式可以跨域呢?

在 JavaScript 中,跨域通信是指在不同源(如不同域名、协议、端口)之间传递数据。以下是常用的跨域通信 API:

1. postMessage

postMessage 是最常见的跨域通信方式。它允许不同窗口(例如,父页面与 iframe,不同浏览器标签页之间,甚至不同的浏览器窗口之间)安全地进行数据传递。

特点:

  • 通过 postMessage,你可以在不同源(如不同域名、协议、端口)之间进行通信。
  • 使用 postMessage 时,需要确保双方都能够验证消息的来源(通过 event.origin)和消息内容。

示例:

  • 发送方(父页面)

    javascript 复制代码
    const iframe = document.getElementById("myIframe");
    iframe.contentWindow.postMessage("Hello from parent!", "http://example.com");
  • 接收方(iframe 页面)

    javascript 复制代码
    window.addEventListener("message", function(event) {
        if (event.origin === "http://example.com") {
            console.log("Received message:", event.data);
        }
    });

2. CORS (Cross-Origin Resource Sharing)

CORS 是一种通过 HTTP 头部来允许跨域请求的机制。它允许服务器指定哪些外部域名的请求是被允许的,从而实现跨域请求。

特点:

  • 需要服务器支持 CORS。
  • 主要用于处理跨域的 AJAX 请求,尤其是当前端使用 fetchXMLHttpRequest 时。
  • 浏览器通过在 HTTP 请求中自动添加特殊的 Origin 头部来确定请求的源,服务器通过响应中的 Access-Control-Allow-Origin 等头部来决定是否允许该请求。

示例:

  • 客户端(发起跨域请求):

    javascript 复制代码
    fetch('http://example.com/data', {
        method: 'GET',
        headers: {
            'Content-Type': 'application/json'
        },
        mode: 'cors'
    })
    .then(response => response.json())
    .then(data => console.log(data));
  • 服务器端(Node.js 示例,允许跨域请求):

    javascript 复制代码
    const express = require('express');
    const app = express();
    
    app.use((req, res, next) => {
        res.setHeader('Access-Control-Allow-Origin', '*');
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
        res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
        next();
    });
    
    app.get('/data', (req, res) => {
        res.json({ message: 'Hello from server!' });
    });
    
    app.listen(3000, () => {
        console.log('Server running on http://localhost:3000');
    });

3. WebSockets

WebSocket 是一种全双工通信协议,允许浏览器和服务器之间进行实时、持久的连接,支持跨域通信。

特点:

  • 可以通过 WebSocket 建立持久的连接,跨越域和协议的限制。
  • 适用于实时数据更新、聊天应用、在线游戏等需要长时间连接的场景。
  • 客户端和服务器通过 ws://wss:// 协议建立 WebSocket 连接。

示例:

  • 客户端

    javascript 复制代码
    const socket = new WebSocket('ws://example.com/socket');
    
    socket.onopen = function(event) {
        console.log('Connection opened:', event);
        socket.send('Hello from client!');
    };
    
    socket.onmessage = function(event) {
        console.log('Message from server:', event.data);
    };
    
    socket.onerror = function(error) {
        console.log('WebSocket Error:', error);
    };

4. window.name

window.name 是一个可以用作跨域通信的技巧。通过将数据存储在 window.name 属性中并跳转到目标页面(可能是一个不同的域),你可以在不同的页面之间共享数据。

特点:

  • window.name 是跨域的,可以在跳转页面后保持数据。
  • 数据在页面跳转后依然可用,因此常用于跨域数据传递。

示例:

  • 客户端(页面 A)

    javascript 复制代码
    window.name = JSON.stringify({ message: 'Hello from A' });
    window.location.href = 'http://example.com/targetPage';
  • 接收方(页面 B)

    javascript 复制代码
    const data = JSON.parse(window.name);
    console.log(data.message); // 输出: Hello from A

5. document.domain

在同一顶级域名下,不同子域之间可以使用 document.domain 来进行跨域通信。通过设置 document.domain 为相同的值,子域之间可以共享资源和通信。

特点:

  • 仅适用于相同顶级域名下的不同子域之间的跨域通信。
  • 使用 document.domain 可以让两个不同子域之间的 JavaScript 进行交互。

示例:

  • 父页面(subdomain1.example.com

    javascript 复制代码
    document.domain = 'example.com';
  • 子页面(subdomain2.example.com

    javascript 复制代码
    document.domain = 'example.com';
  • 这样,subdomain1.example.comsubdomain2.example.com 之间的 JavaScript 就可以互相访问了。

6. Server-Sent Events (SSE)

SSE 是一种单向的通信方式,服务器可以通过它推送信息到客户端。适用于服务器向多个客户端推送实时事件的场景。

特点:

  • 服务器向客户端推送数据,支持跨域。
  • 与 WebSocket 不同,SSE 是单向通信,客户端无法向服务器发送消息。

示例:

  • 客户端

    javascript 复制代码
    const eventSource = new EventSource('http://example.com/events');
    
    eventSource.onmessage = function(event) {
        console.log('New event:', event.data);
    };
    
    eventSource.onerror = function(error) {
        console.error('EventSource failed:', error);
    };
  • 服务器端

    javascript 复制代码
    const express = require('express');
    const app = express();
    
    app.get('/events', (req, res) => {
        res.setHeader('Content-Type', 'text/event-stream');
        res.setHeader('Cache-Control', 'no-cache');
        res.setHeader('Connection', 'keep-alive');
        res.flushHeaders();
    
        setInterval(() => {
            res.write('data: Hello from server\n\n');
        }, 1000);
    });
    
    app.listen(3000, () => {
        console.log('Server running on http://localhost:3000');
    });

总结

常见的 JavaScript 跨域通信 API 有:

  • postMessage:适用于不同窗口、iframe 或跨源通信。
  • CORS:允许跨域的 AJAX 请求。
  • WebSockets:用于实时双向通信,跨域支持。
  • window.name:跨域数据传递的技巧。
  • document.domain:适用于同一顶级域名下的不同子域之间的跨域通信。
  • Server-Sent Events (SSE):服务器向客户端单向推送数据,支持跨域。

最终选择了postMessage API

根据代码编辑器,可以看到,我们采用的是postMessage API,如下所示:

js 复制代码
const iframe = document.getElementById('child');
const message = [
 {
                type: 'html',
                content: '<h1 id="title">Hello,eveningwater!</h1>'
 },
            {
                type: 'css',
                content: 'h1{color:#2396ef;}'
            },
            {
                type: 'js',
                content: 'document.getElementById("title").onclick = () => {alert("Hello,eveningwater!");}'
            }
];
iframe.addEventListener("load", () => {
    iframe.contentWindow.postMessage(message, "*");
});

我们只需要在接收端监听一下message事件即可,如下所示:

js 复制代码
 window.addEventListener("message", function (event) {
    if (Array.isArray(event.data)) {
      // 拿到数据赋值给编辑器即可
      setEditorContent(event.data);
    }
  });

感谢阅读本文。

相关推荐
yunvwugua__2 小时前
Python训练营打卡 Day26
前端·javascript·python
码农捻旧4 小时前
解决Mongoose “Cannot overwrite model once compiled“ 错误的完整指南
javascript·数据库·mongodb·node.js·express
淡笑沐白4 小时前
探索Turn.js:打造惊艳的3D翻页效果
javascript·html5·turn.js
sunxunyong4 小时前
yarn任务筛选spark任务,判断内存/CPU使用超过限制任务
javascript·ajax·spark
Ynov5 小时前
详细解释api
javascript·visual studio code
三天不学习5 小时前
一文讲透 Vue3 + Three.js 材质属性之皮革篇【扫盲篇】
javascript·webgl·three.js·材质
不爱吃饭爱吃菜6 小时前
uniapp微信小程序-长按按钮百度语音识别回显文字
前端·javascript·vue.js·百度·微信小程序·uni-app·语音识别
程序员拂雨7 小时前
Angular 知识框架
前端·javascript·angular.js
zhengddzz8 小时前
从卡顿到丝滑:JavaScript性能优化实战秘籍
开发语言·javascript·性能优化
Go_going_8 小时前
ajax,Promise 和 fetch
javascript·ajax·okhttp