node.js - 使用 devtool 协议(protocol)从嵌入式 iframe 捕获请求(XHR、JS、CSS)

标签 node.js google-chrome iframe puppeteer chrome-devtools-protocol

对于上下文,我正在使用 Nodejs 和 puppeteer 开发一个综合监控工具。 对于定义场景的每个步骤,我都会捕获屏幕截图、 waterfall 和性能指标。

我的问题出在 waterfall 上,我以前使用过 puppeter-har,但这个包无法捕获导航之外的请求。 因此我使用这段代码来捕获所有有趣的请求:

const {harFromMessages} = require('chrome-har');
// Event types to observe for waterfall saving (probably overkill, I just set all events of Page and Network)
const observe = [
  'Page.domContentEventFired',
  'Page.fileChooserOpened',
  'Page.frameAttached',
  'Page.frameDetached',
  'Page.frameNavigated',
  'Page.interstitialHidden',
  'Page.interstitialShown',
  'Page.javascriptDialogClosed',
  'Page.javascriptDialogOpening',
  'Page.lifecycleEvent',
  'Page.loadEventFired',
  'Page.windowOpen',
  'Page.frameClearedScheduledNavigation',
  'Page.frameScheduledNavigation',
  'Page.compilationCacheProduced',
  'Page.downloadProgress',
  'Page.downloadWillBegin',
  'Page.frameRequestedNavigation',
  'Page.frameResized',
  'Page.frameStartedLoading',
  'Page.frameStoppedLoading',
  'Page.navigatedWithinDocument',
  'Page.screencastFrame',
  'Page.screencastVisibilityChanged',
  'Network.dataReceived',
  'Network.eventSourceMessageReceived',
  'Network.loadingFailed',
  'Network.loadingFinished',
  'Network.requestServedFromCache',
  'Network.requestWillBeSent',
  'Network.responseReceived',
  'Network.webSocketClosed',
  'Network.webSocketCreated',
  'Network.webSocketFrameError',
  'Network.webSocketFrameReceived',
  'Network.webSocketFrameSent',
  'Network.webSocketHandshakeResponseReceived',
  'Network.webSocketWillSendHandshakeRequest',
  'Network.requestWillBeSentExtraInfo',
  'Network.resourceChangedPriority',
  'Network.responseReceivedExtraInfo',
  'Network.signedExchangeReceived',
  'Network.requestIntercepted'
];

在步骤的开始:

// list of events for converting to HAR
  const events = [];

  client = await page.target().createCDPSession();
  await client.send('Page.enable');
  await client.send('Network.enable');
  observe.forEach(method => {
    client.on(method, params => {
      events.push({ method, params });
    });
  });

在步骤结束时:

waterfall = await harFromMessages(events);

它适用于导航事件,也适用于 Web 应用程序内部的导航。 但是,我尝试监视的 Web 应用程序具有包含主要内容的 iframe。 我希望在我的 waterfall 中看到 iframe 请求。

那么几个问题:

  • 为什么 Network.responseReceived 或任何其他事件没有捕获此请求?
  • 是否可以捕获此类请求?

到目前为止,我已经修改了 devtool 协议(protocol)文档,但我无法使用任何东西。 我发现最接近我的问题的是这个问题: How can I receive events for an embedded iframe using Chrome Devtools Protocol?

我的猜测是,我必须为我可能遇到的每个 iframe 启用网络。 我没有找到任何方法来做到这一点。如果有办法用 devtool 协议(protocol)来实现,我用 nodsjs 和 puppeteer 来实现它应该没有问题。

感谢您的见解!

编辑 18/08 :

在对该主题进行更多搜索(主要是进程外 iframe)之后,互联网上的许多人都指出了该响应: https://bugs.chromium.org/p/chromium/issues/detail?id=924937#c13

答案是问题状态:

请注意,最简单的解决方法是 --disable-features 标志。

That said, to work with out-of-process iframes over DevTools protocol, you need to use Target [1] domain:

  • Call Target.setAutoAttach with flatten=true;
  • You'll receive Target.attachedToTarget event with a sessionId for the iframe;
  • Treat that session as a separate "page" in chrome-remote-interface. Send separate protocol messages with additional sessionId field:
    {id: 3, sessionId: "", method: "Runtime.enable", params: {}}
  • You'll get responses and events with the same "sessionId" field which means they are coming from that frame. For example:
    {sessionId: "", method: "Runtime.consoleAPICalled", params: {...}}

但是我仍然无法实现它。

我正在尝试这个,主要基于 puppeteer 操纵者:

  const events = [];
  const targets = await browser.targets();
  const nbTargets = targets.length;
  for(var i=0;i<nbTargets;i++){
    console.log(targets[i].type());
    if (targets[i].type() === 'page') {
      client = await targets[i].createCDPSession();

      await client.send("Target.setAutoAttach", {
        autoAttach: true,
        flatten: true,
        windowOpen: true,
        waitForDebuggerOnStart: false // is set to false in pptr
      })

      await client.send('Page.enable');
      await client.send('Network.enable');

      observeTest.forEach(method => {
        client.on(method, params => {
          events.push({ method, params });
        });
      });
    }
  };

但我仍然没有在 iframe 内的 Web 应用程序中获得预期的导航输出。

但是,我能够在加载 iframe 的步骤中捕获所有请求。 我想念的是在正确导航之外发生的请求。

有没有人知道将上述 chromium 响应集成到 puppeteer 中?谢谢!

最佳答案

我一直在看错误的一面。 chrome 网络事件被正确捕获,如果我早些时候检查“事件”变量,我会早先看到这一点。 问题来 self 使用的“chrome-har”包:

waterfall = await harFromMessages(events);

页面期望页面和 iframe 主事件与请求出现在同一批事件中。否则请求“目前无法映射到任何页面”。

我的场景的步骤有时是同一个 web 应用程序中的导航(=无导航事件),我没有这些事件,chrome-har 无法映射请求,因此发送了一个空的 .har

希望它可以帮助其他人,我搞砸了这个调试...

关于node.js - 使用 devtool 协议(protocol)从嵌入式 iframe 捕获请求(XHR、JS、CSS),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63357370/

相关文章:

node.js - 如何将 Slack 机器人扩展到 1000 个团队

node.js - Azure DevOps Pipelines 将 Node.js 脚本作为一个步骤运行

python-3.x - 使用 Selenium 的 headless Chrome - 401 未经授权的访问

javascript - 如何强制 JavaScript 深度复制字符串?

javascript - Android 浏览器 html5 音频无法播放

javascript - 根据内容更改 iframe 高度

javascript - 根据字段的值获取对象的最后一次出现

javascript - 在具有不同域 url 的页面内使用 iframe 时,Internet Explorer 中的访问被拒绝

javascript - 制作自适应 iframe,然后在单击按钮时允许全屏显示

node.js - 使用 express-session、connect-mongo 和 mongoose 存储 session