CrossBridge 技术设计详细方案
🔧 核心技术选型
1. 通信技术栈
- SharedWorker: 同域独立标签页通信的主要方案
- PostMessage: iframe 与父页面通信的标准方案
- BroadcastChannel: 跨域标签页通信的备选方案
- Proxy: 用于 API 代理和消息拦截
- Set/Map: 高效的页面和消息管理
2. 存储技术栈
- Memory Cache: 高频访问的临时数据
- SessionStorage: 会话级别的消息缓存
- LocalStorage: 持久化的配置和重要消息
- IndexedDB: 大量消息数据的结构化存储
📐 详细技术设计
1. 核心通信引擎设计
typescript
// 通信引擎核心接口
interface ICommunicationEngine {
// 初始化引擎
initialize(config: EngineConfig): Promise<void>;
// 发送消息
send(message: Message): Promise<boolean>;
// 接收消息处理
onMessage(handler: MessageHandler): void;
// 获取连接状态
getConnectionStatus(): ConnectionStatus;
// 销毁引擎
destroy(): void;
}
// 引擎配置
interface EngineConfig {
pageId: string;
role: PageRole;
adapters: AdapterConfig[];
queue: QueueConfig;
storage: StorageConfig;
}
// 消息结构
interface Message {
id: string;
type: string;
event: string;
data: any;
from: string;
to?: string | string[];
timestamp: number;
ttl?: number;
priority?: number;
}2. 适配器系统设计
typescript
// 适配器基类
abstract class BaseAdapter {
protected config: AdapterConfig;
protected engine: ICommunicationEngine;
constructor(config: AdapterConfig, engine: ICommunicationEngine) {
this.config = config;
this.engine = engine;
}
abstract connect(): Promise<void>;
abstract disconnect(): void;
abstract send(message: Message): Promise<boolean>;
abstract onMessage(handler: MessageHandler): void;
abstract isSupported(): boolean;
}
// SharedWorker 适配器
class SharedWorkerAdapter extends BaseAdapter {
private worker: SharedWorker | null = null;
private port: MessagePort | null = null;
async connect(): Promise<void> {
if (!this.isSupported()) {
throw new Error('SharedWorker not supported');
}
this.worker = new SharedWorker('/cross-bridge-worker.js');
this.port = this.worker.port;
this.port.onmessage = (event) => {
this.handleMessage(event.data);
};
this.port.start();
// 注册页面
await this.registerPage();
}
async send(message: Message): Promise<boolean> {
if (!this.port) return false;
this.port.postMessage(message);
return true;
}
isSupported(): boolean {
return typeof SharedWorker !== 'undefined';
}
private async registerPage(): Promise<void> {
const registrationMessage: Message = {
id: generateId(),
type: 'system',
event: 'page-register',
data: {
pageId: this.config.pageId,
role: this.config.role,
origin: window.location.origin,
},
from: this.config.pageId,
timestamp: Date.now(),
};
await this.send(registrationMessage);
}
}
// PostMessage 适配器
class PostMessageAdapter extends BaseAdapter {
private targetWindow: Window | null = null;
private targetOrigin: string = '*';
async connect(): Promise<void> {
// 根据角色确定目标窗口
if (this.config.role === 'child') {
this.targetWindow = window.parent;
} else if (this.config.role === 'parent') {
// 父页面需要管理多个 iframe
this.setupIframeManagement();
}
// 监听消息
window.addEventListener('message', this.handlePostMessage.bind(this));
}
async send(message: Message): Promise<boolean> {
if (!this.targetWindow) return false;
this.targetWindow.postMessage(message, this.targetOrigin);
return true;
}
private handlePostMessage(event: MessageEvent): void {
// 验证消息来源
if (!this.isValidOrigin(event.origin)) {
return;
}
const message = event.data as Message;
this.handleMessage(message);
}
private setupIframeManagement(): void {
// 管理多个 iframe 的引用
const iframes = new Map<string, HTMLIFrameElement>();
// 监听 iframe 加载
document.addEventListener('DOMContentLoaded', () => {
const iframeElements = document.querySelectorAll(
'iframe[data-bridge-id]'
);
iframeElements.forEach((iframe) => {
const id = iframe.getAttribute('data-bridge-id');
if (id) {
iframes.set(id, iframe as HTMLIFrameElement);
}
});
});
}
}3. 消息队列系统设计
typescript
// 消息队列管理器
class MessageQueueManager {
private queues: Map<string, MessageQueue> = new Map()
private storage: StorageManager
private config: QueueConfig
constructor(storage: StorageManager, config: QueueConfig) {
this.storage = storage
this.config = config
this.startCleanupTimer()
}
// 入队消息
async enqueue(message: Message): Promise<void> {
const queueKey = this.getQueueKey(message)
let queue = this.queues.get(queueKey)
if (!queue) {
queue = new MessageQueue(queueKey, this.config)
this.queues.set(queueKey, queue)
}
await queue.enqueue(message)
// 持久化存储
if (this.shouldPersist(message)) {
await this.storage.store(queueKey, message, this.getStorageConfig(message))
}
}
// 出队消息
async dequeue(queueKey: string): Promise<Message[]> {
const queue = this.queues.get(queueKey)
if (!queue) return []
const messages = await queue.dequeue()
// 从持久化存储中获取
const storedMessages = await this.storage.retrieve(queueKey)
return [...messages, ...storedMessages]
}
// 获取队列键
private getQueueKey(message: Message): string {
return `${message.to || 'broadcast'}-${message.type}`
}
// 判断是否需要持久化
private shouldPersist(message: Message): boolean {
const messageTypeConfig = this.config.messageTypes[message.type]
return messageTypeConfig?.persistent || false
}
// 获取存储配置
private getStorageConfig(message: Message): StorageConfig {
const messageTypeConfig = this.config.messageTypes[message.type];
return {
type: messageTypeConfig?.storage || 'memory',
ttl: messageTypeConfig?.ttl
};
}
}4. 存储管理器设计
typescript
// 存储策略接口
interface StorageStrategy {
get<T>(key: string): Promise<T | null>;
set<T>(key: string, value: T, ttl?: number): Promise<void>;
remove(key: string): Promise<void>;
clear(): Promise<void>;
}
// 存储管理器
class StorageManager {
private strategies = new Map<StorageType, StorageStrategy>();
constructor(config: StorageConfig) {
this.initializeStrategies();
}
private initializeStrategies(): void {
this.strategies.set('memory', new MemoryStorage());
this.strategies.set('local', new LocalStorageStrategy());
this.strategies.set('session', new SessionStorageStrategy());
// IndexedDB for large data
if (typeof indexedDB !== 'undefined') {
this.strategies.set('indexeddb', new IndexedDBStorage());
}
}
async store<T>(key: string, value: T, config: StorageItemConfig): Promise<void> {
const strategy = this.strategies.get(config.type);
if (!strategy) throw new Error(`Storage type ${config.type} not ready`);
await strategy.set(key, value, config.ttl);
}
}5. 完全跨域通信扩展设计
为了支持不同一级域名的通信,设计了两种扩展适配器:
5.1 WebSocket 中继适配器 (WebSocketRelayAdapter)
适用于高性能、实时通讯场景。
- 原理: 客户端 A -> WebSocket 服务端 -> 客户端 B
- 协议: 自定义 JSON 协议,不仅包含数据,还包含
auth(认证),heartbeat(心跳),relay(中继指令)。 - 安全: 基于 Token 的身份验证,防止未授权访问。
typescript
interface RelayMessage {
type: 'auth' | 'heartbeat' | 'relay';
from: string; // pageId
to?: string; // target pageId
payload: any;
}5.2 Iframe 桥接适配器 (IframeBridgeAdapter)
适用于无后端开发资源的场景。
- 原理:
- 页面 A 和 页面 B 都加载同一个跨域 iframe (
bridge.html)。 - 利用iframe的
postMessage作为中转枢纽。 bridge.html维护一个window注册表,负责路由消息。
- 页面 A 和 页面 B 都加载同一个跨域 iframe (
6. 总结
本设计采用插件化架构,核心只负责生命周期和消息分发,具体通信由适配器实现。 通过引入 消息队列 和 多级存储,解决了复杂的异步加载和数据持久化问题。 通过 WebSocket Relay 和 Iframe Bridge,实现了对全场景跨域通信的覆盖。