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

跨域场景下如何将另一页面的MediaStream传输至当前页替换伪造流

跨域页面媒体流替换实现方案

你当前是基于Puppeteer操控同一浏览器实例下的两个跨域页面,可通过以下两种成熟方案实现需求:

方案1:Node层中转流(无浏览器配置修改,兼容性强)

核心逻辑是通过Puppeteer的上下文通信能力,绕开页面跨域限制,在Node层完成流的中转:

  • 首先在第二个页面捕获视频流,切片后通过Puppeteer暴露的方法传到Node层
  • Node层暂存切片后,传递给第一个页面合成新的MediaStream,替换原有伪造流即可

完整实现代码:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  // 打开两个业务页面
  const page1 = await browser.newPage();
  await page1.goto('https://域名1页面地址');
  const page2 = await browser.newPage();
  await page2.goto('https://域名2页面地址');

  // 给page2暴露上传流切片的Node方法
  const streamChunks = [];
  await page2.exposeFunction('pushStreamChunk', (base64Chunk) => {
    streamChunks.push(Buffer.from(base64Chunk, 'base64'));
  });

  // page2内捕获视频流并切片上传
  await page2.evaluate(() => {
    const videoEl = document.querySelector('#video');
    const originStream = videoEl.captureStream(60);
    const recorder = new MediaRecorder(originStream, { mimeType: 'video/webm;codecs=vp9' });
    recorder.ondataavailable = (e) => {
      if (!e.data.size) return;
      const reader = new FileReader();
      reader.onload = () => window.pushStreamChunk(reader.result.split(',')[1]);
      reader.readAsDataURL(e.data);
    };
    recorder.start(100); // 每100ms切一个分片,可根据延迟需求调整
  });

  // 给page1暴露拉取流切片的方法
  await page1.exposeFunction('pullStreamChunk', () => streamChunks.shift()?.toString('base64') || null);

  // page1内合成流并替换原有伪造流
  await page1.evaluate(() => {
    const mediaSource = new MediaSource();
    const tempVideo = document.createElement('video');
    tempVideo.muted = true;
    tempVideo.src = URL.createObjectURL(mediaSource);
    tempVideo.play().catch(() => {});

    mediaSource.onsourceopen = () => {
      const sourceBuffer = mediaSource.addSourceBuffer('video/webm;codecs=vp9');
      // 循环拉取分片拼接
      function loadNextChunk() {
        window.pullStreamChunk().then(chunkBase64 => {
          if (chunkBase64 && !sourceBuffer.updating) {
            const uint8 = Uint8Array.from(atob(chunkBase64), c => c.charCodeAt(0));
            sourceBuffer.appendBuffer(uint8);
            // 清理已播放的缓存避免内存溢出
            if (sourceBuffer.buffered.length) {
              sourceBuffer.remove(0, sourceBuffer.buffered.end(0) - 3);
            }
          }
          setTimeout(loadNextChunk, 50);
        });
      }
      loadNextChunk();
    };

    // 替换原有伪造流逻辑,和你之前同页面的写法一致
    const newStream = tempVideo.captureStream(60);
    navigator.mediaDevices.getDisplayMedia = () => Promise.resolve(newStream);
  });
})();

方案2:关闭浏览器跨域限制,点对点传输(延迟更低)

如果是测试场景或者允许修改浏览器启动参数,可以直接关闭浏览器跨域安全限制,两个页面通过RTCPeerConnection点对点传输媒体流,不需要Node层中转,延迟最低:

  1. 启动浏览器时添加关闭安全限制的参数:
const browser = await puppeteer.launch({
  args: ['--disable-web-security', '--user-data-dir=/tmp/chrome-temp-profile']
});
  1. 在page2生成媒体流和SDP offer,通过Puppeteer传递给page1
  2. page1生成SDP answer回传给page2,建立连接后直接拿到传输的媒体流替换原有伪造流即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 10:06:03