cdp协议简介

啥是cdp

根据官网的说法,cdp(Chrome DevTools Protocol) 容许咱们检测,调试Chromium, Chrome 和其余基于 Blink的 浏览器. 这个协议被普遍使用. 其中最著名的是 Chrome DevTools 和 puppeteer,协议的api也由这个团队维护。html

使用cdp的姿式

若是在浏览器中,当你打开devtools时,其实你已经在使用cdp了,只是感知不深罢了,一种办法能够更直观的感知cdp,就是打开devtools的devtools,具体操做以下:git

  1. 将开发者工具设置为独立窗口,dock side点第一个
  2. 在开发者工具上再使用快捷键ctrl+shift+i,就能够打开开发者工具的开发者工具了(禁止套娃),能够看到开发者工具的url是devtools://devtools/bundled/xxx.html?xx,如今在新打开的开发者工具的console里面,输入下面的代码:
let Main = await import('./main/main.js');
Main.MainImpl.sendOverProtocol('Runtime.evaluate', {expression: 'alert (12345)'});

这时网页会alert 12345,你会发现平时在控制台简单的代码执行,实际上是经过cdp远程调用网页的js引擎去执行再返回结果的。github

除此以外,protocol monitor也能够帮助咱们更直观的理解cdp。web

几个重要的URL

当一个页面暴露出它的remote debugging port时,咱们就能够借助cdp来对这个网页进行remote debugging了。因为cdp是借助websocket实现的,因此,在一切开始以前,有两个url是比较重要的
http://localhost:[port]/json/list
http://localhost:[port]/json/version
这两个url,可让咱们拿到网页的websocket url,json/list返回的数据相似于:chrome

[
{
description: "",
devtoolsFrontendUrl: "/devtools/inspector.html?ws=localhost:8080/devtools/page/a31c4d5c-b0df-48e8-8dcc-7c98964e2ebe",
id: "a31c4d5c-b0df-48e8-8dcc-7c98964e2ebe",
title: "",
type: "page",
url: "xxx://xxx",
webSocketDebuggerUrl: "ws://localhost:8080/devtools/page/a31c4d5c-b0df-48e8-8dcc-7c98964e2ebe"
}
]

其中webSocketDebuggerUrl就是咱们须要的打开remote debugging 的钥匙express

重头戏websocket

接下来咱们连上ws,就能够愉快的远程操做页面了,正如chrome devtools所作的那样,下面是一个例子:json

const WebSocket = require('ws');
const puppeteer = require('puppeteer');

(async () => {
  // Puppeteer launches browser with a --remote-debugging-port=0 flag,
  // parses Remote Debugging URL from Chromium's STDOUT and exposes
  // it as |browser.wsEndpoint()|.
  const browser = await puppeteer.launch();

  // Create a websocket to issue CDP commands.
  const ws = new WebSocket(browser.wsEndpoint(), {perMessageDeflate: false});
  await new Promise(resolve => ws.once('open', resolve));
  console.log('connected!');

  ws.on('message', msg => console.log(msg));

  console.log('Sending Target.setDiscoverTargets');
  ws.send(JSON.stringify({
    id: 1,
    method: 'Target.setDiscoverTargets',
    params: {
      discover: true
    },
  }));
})();

更多例子能够在这里api

jsonRPC

如上面例子所示,当ws链接后,一个发给浏览器的指令大概包括3部分id,method,params,好比一个执行一段console.log('hello')代码的指令:浏览器

{
  "id": 235,
  "method": "Runtime.evaluate",
  "params": {
    "expression": "console.log('hello');",
    "objectGroup": "console",
    "includeCommandLineAPI": true,
    "silent": false,
    "contextId": 1,
    "returnByValue": false,
    "generatePreview": true,
    "userGesture": true,
    "awaitPromise": false
  }
}

chrome devtools能够完成的功能很是庞大,而这些功能基本都是使用这样的一个个指令实现的,让人想起那句古老的中国名言:九层之台,起于垒土。本文完websocket

参考资料:
https://chromedevtools.github.io/devtools-protocol
https://github.com/aslushnikov/getting-started-with-cdp/blob/master/README.md