跨域场景下如何将另一页面的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层中转,延迟最低:
- 启动浏览器时添加关闭安全限制的参数:
const browser = await puppeteer.launch({ args: ['--disable-web-security', '--user-data-dir=/tmp/chrome-temp-profile'] });
- 在page2生成媒体流和SDP offer,通过Puppeteer传递给page1
- page1生成SDP answer回传给page2,建立连接后直接拿到传输的媒体流替换原有伪造流即可
内容的提问来源于stack exchange,提问作者mhammad
相关产品推荐
相关产品推荐

