You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Promise的then回调中向iframe发送postMessage获取用户连接信息?

在Promise的then回调中向iframe父页面发送postMessage并同步连接用户数据

问题背景

我有一段基于Promise的WebRTC音视频应用代码,目前通过带定时器的函数循环向父页面(嵌入该WebRTC页面的Flask应用)发送postMessage,但希望能直接在Promise的then回调中发送状态,同时需要实时获取当前连接用户的相关数据,用来控制Flask应用里的功能锁定/解锁。

现有代码

const socket = io('/')
const videoGrid = document.getElementById('video-grid')
const myPeer = new Peer(undefined, {
  path: '/peerjs',
  host: '/',
  port: '3000'
})
const peers = {}
let myVideoStream;
const myVideo = document.createElement('video')
myVideo.muted = true;

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function brodcastStatus(postMsg) {
  for (let i = 0; i < 10; i++) {
    parent.postMessage(postMsg, "*");
    console.log(postMsg)
    await sleep(1500)
  }
}

if (KIND === 'server'){
  Promise.resolve(navigator.mediaDevices.getUserMedia({
    video: {
      width: 1920,
      height: 1080,
      aspectRatio: { ideal: 1.7777777778 },
      frameRate: { max: 24, }
    },
    audio: true
  })).then(stream => {
    brodcastStatus("server | camera | mic")
    myVideoStream = stream;

    myPeer.on('call', call => {
      call.answer(stream)
      const video = document.createElement('video')
      call.on('stream', userVideoStream => {
        addVideoStream(video, userVideoStream)
      })
    })

    socket.on('user-connected', userId => {
      connectToNewUser(userId, stream)
    })

  }).catch(() => {
    Promise.resolve(navigator.mediaDevices.getUserMedia({
      video: {
        width: 1920,
        height: 1080,
        aspectRatio: { ideal: 1.7777777778 },
        frameRate: { max: 24, }
      },
      audio: false
    })).then(stream => {
      brodcastStatus("server | camera | no mic")
      myVideoStream = stream;

      myPeer.on('call', call => {
        call.answer(stream)
        const video = document.createElement('video')
        call.on('stream', userVideoStream => {
          addVideoStream(video, userVideoStream)
        })
      })

      socket.on('user-connected', userId => {
        connectToNewUser(userId, stream)
      })

    }).catch(() => {
      console.log("nocamera or microphone")
    })
  })
}else if (KIND === 'client'){
  Promise.resolve(navigator.mediaDevices.getUserMedia({
    video: false,
    audio: true
  })).then(stream => {
    brodcastStatus("client | no camera | mic")
    myVideoStream = stream;

    myPeer.on('call', call => {
      call.answer(stream)
      const video = document.createElement('video')
      call.on('stream', userVideoStream => {
        addVideoStream(video, userVideoStream)
      })
    })

    socket.on('user-connected', userId => {
      connectToNewUser(userId, stream)
    })

  }).catch(() => {
    console.log("Client")
    newStream = new MediaStream();
    stream = newStream;
    myVideoStream = stream;
    myPeer.on('call', call => {
      call.answer(stream)
      const video = document.createElement('video')
      call.on('stream', userVideoStream => {
        addVideoStream(video, userVideoStream)
      })
    })
  
    socket.on('user-connected', userId => {
      connectToNewUser(userId, stream)
    })    

  })

}

socket.on('user-disconnected', userId => {
  if (peers[userId]) peers[userId].close()
})


myPeer.on('open', id => {
  socket.emit('join-room', ROOM_ID, id)
})


function connectToNewUser(userId, stream) {
  const call = myPeer.call(userId, stream)
  const video = document.createElement('video')
  call.on('stream', userVideoStream => {
    addVideoStream(video, userVideoStream)
  })
  call.on('close', () => {
    video.remove()
  })

  peers[userId] = call
}


function addVideoStream(video, stream) {
  video.srcObject = stream
  video.setAttribute("style", "object-fit:cover; background: transparent url(/images/New_DACL_Logo.png) no-repeat center center; background-size: auto; overflow: hidden;")
  video.addEventListener('loadedmetadata', () => {
  })
  videoGrid.append(video)
}

解决方案

1. 在Promise的then回调中直接发送结构化消息

不需要循环定时发送,在媒体流获取成功的then回调里直接发送结构化数据(用对象代替字符串,方便父页面解析),同时包含当前连接用户数:

// 替换原有brodcastStatus调用,比如在server端带音视频的then回调中:
.then(stream => {
  // 发送结构化状态数据
  parent.postMessage({
    type: 'device_status',
    role: 'server',
    hasCamera: true,
    hasMic: true,
    connectedUsers: Object.keys(peers).length
  }, 'https://your-flask-domain.com'); // 替换为你的Flask应用域名,不要用*提升安全性
  
  myVideoStream = stream;
  // ...原有逻辑
})

在其他then回调和catch分支中也做类似修改,比如server端仅摄像头的情况:

.then(stream => {
  parent.postMessage({
    type: 'device_status',
    role: 'server',
    hasCamera: true,
    hasMic: false,
    connectedUsers: Object.keys(peers).length
  }, 'https://your-flask-domain.com');
  
  myVideoStream = stream;
  // ...原有逻辑
})

2. 实时同步连接用户数量

在用户连接和断开时,主动向父页面发送更新:

  • 用户连接时:
socket.on('user-connected', userId => {
  connectToNewUser(userId, stream);
  // 发送用户数更新
  parent.postMessage({
    type: 'user_count',
    connectedUsers: Object.keys(peers).length
  }, 'https://your-flask-domain.com');
});
  • 用户断开时:
socket.on('user-disconnected', userId => {
  if (peers[userId]) peers[userId].close();
  delete peers[userId]; // 清理peers对象,保证计数准确
  parent.postMessage({
    type: 'user_count',
    connectedUsers: Object.keys(peers).length
  }, 'https://your-flask-domain.com');
});

3. 父页面(Flask应用)接收消息的处理逻辑

在Flask应用的页面中添加监听,根据收到的数据控制功能:

window.addEventListener('message', (event) => {
  // 验证消息来源,防止非法请求
  if (event.origin !== 'https://your-webrtc-domain.com') return;
  
  const data = event.data;
  switch(data.type) {
    case 'device_status':
      // 处理设备状态,比如显示当前角色和设备情况
      console.log(`角色:${data.role},摄像头:${data.hasCamera},麦克风:${data.hasMic}`);
      break;
    case 'user_count':
      // 根据连接用户数锁定/解锁功能
      const targetBtn = document.getElementById('target-feature');
      targetBtn.disabled = data.connectedUsers === 0;
      break;
  }
});

注意事项

  • 始终指定postMessage的目标域名,不要用*,避免安全风险
  • 父页面一定要验证消息来源,防止跨域恶意消息
  • 结构化数据比字符串更易维护和解析,推荐使用对象格式传递信息

内容的提问来源于stack exchange,提问作者itIsWhatItIs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 02:10:25