编程式调试node程序的利器chrome-remote-interface

本文介绍了chrome-remote-interface,一个基于Chrome调试协议的Node.js调试工具。通过命令行,我们可以安装、启动调试目标,并利用其API进行编程式调试。内容包括安装、启动调试目标、使用命令行工具及API接口的详细操作。

编程式调试node程序的利器chrome-remote-interface

简介

chrome-remote-interface是chrome调试协议的第三方调试客户端实现,该项目开源,提供了命令行工具,且为node程序提供了api。
chrome-remote-interface为基于chrome调试协议编写自己的node调试工具提供了便捷的途径,因为利用它,你不需要基于原始的协议通过websocket编程去开发调试工具了。
项目地址https://github.com/cyrus-and/chrome-remote-interface

使用命令行

安装

通过npm进行安装

npm install chrome-remote-interface

启动调试目标

chrome-remote-interface基于chrome调试协议,因此其支持调试chrome浏览器和node运行环境。
无论哪种调试目标,其启动时都应该指定调试端口。
如果要调试chrome浏览器,应该在启动chrome时添加–remote-debugging-port参数,如下:

goole-chrome --remote-debugging-port=9222

如果调试node,在启动时添加–inspect参数,如下:

node --inspect=9222 app.js

此时,node会输出:

Debugger listening on port 9222.
Warning: This is an experimental feature and could change at any time.
To start debugging, open the following URL in Chrome:
    chrome-devtools://devtools/remote/serve_file/@60cd6e859b9f557d2312f5bf532f6aec5f284980/inspector.html?experiments=true&v8only=true&ws=localhost:9222/2894362d-f2d1-4f3b-a9e8-4e27da5714ef

题外话:如果只是希望调试node,并不打算开发一个调试node的工具的话,根据提示中的url,在chrome中打开就直接可以用chrome的开发工具调试了。

体验命令行

  • 查看全部命令

    在终端输入chrome-remote-interface并回车,可看到如下输出:

    Usage: chrome-remote-interface [options] [command]
    
    Commands:
    
    inspect [options] [<target>] inspect a target (defaults to the current tab)
    list                   list all the available tabs
    new [<url>]            create a new tab
    activate <id>          activate a tab by id
    close <id>             close a tab by id
    version                show the browser version
    protocol [options]     show the currently available protocol descriptor
    
    Options:
    
    -h, --help         output usage information
    -t, --host <host>  HTTP frontend host
    -p, --port <port>  HTTP frontend port

    其中,new和close是针对浏览器的tab的命令,不要针对node来运行。

  • 查看所有页面实例

    chrome-remote-interface -t 127.0.0.1 -p 9222 list

    输出如下:

    [ { description: 'node.js instance',
    devtoolsFrontendUrl: 'https://chrome-devtools-frontend.appspot.com/serve_file/@60cd6e859b9f557d2312f5bf532f6aec5f284980/inspector.html?experiments=true&v8only=true&ws=localhost:9222/2894362d-f2d1-4f3b-a9e8-4e27da5714ef',
    faviconUrl: 'https://nodejs.org/static/favicon.ico',
    id: '2894362d-f2d1-4f3b-a9e8-4e27da5714ef',
    title: 'app.js',
    type: 'node',
    url: 'file:///Users/renbaogang/git/enzyme.node/app.js',
    webSocketDebuggerUrl: 'ws://localhost:9222/2894362d-f2d1-4f3b-a9e8-4e27da5714ef' } ]

    其中devtoolsFrontendUrl可以在chrome地址栏中回车该url,打开chrome的开发工具,可以直接用该工具调试。和启动node时,node提示的url是一个用途。
    id是当前页面标识。
    url是当前页面url。
    webSocketDebuggerUrl是node提供的ws协议的调试服务,调试客户端需要通过该url连接到调试服务。

  • 查看调试目标版本

    chrome-remote-interface -t 127.0.0.1 -p 9222 version

    输出:

    [ { Browser: 'node.js/v7.0.0', 'Protocol-Version': '1.1' } ]
  • 查看调试目标支持的调试协议

    chrome-remote-interface -t 127.0.0.1 -p 9222 protocol

    输出:

    { 
    remote: false,
    descriptor: {
        { version: { major: '1', minor: '2' },
        domains:[略]
    }
    }

    remote:false说明协议内容是工具自带的协议文件,并不是来自调试目标。
    如果要获取调试目标的协议内容要添加-r选项,如:

    chrome-remote-interface -t 127.0.0.1 -p 9222 protocol -r

    输出:

    { 
    remote: true,
    descriptor: {
        { version: { major: '1', minor: '1' },
        domains:[略]
    }
    }
  • 调试命令

    chrome-remote-interface -t 127.0.0.1 -p 9222 inspect -r
    -r 表示应用调试目标提供的协议描述文件
    通过inspect可以调试node或chrome所支持的各个域。

    Console域体验

    >>> Console.enable()
    { result: {} }
    >>> Console.clearMessages()
    { result: {} }

    Debugger域体验

    >>> Debugger.enable()
    { result: {} }
    >>> Debugger.setBreakpointsActive({active:true})
    { result: {} }

    HeapProfiler域体验

    >>> HeapProfiler.enable()
    { result: {} }
    >>> HeapProfiler.startTrackingHeapObjects({trackAllocations:true})
    { result: {} }

    Profiler域体验

    >>> Profiler.enable()
    { result: {} }
    >>> Profiler.start()
    { result: {} }
    >>> Profiler.stop()
    { result: 
    { profile: 
      { nodes: 
         [ { id: 1,
             callFrame: 
              { functionName: '(root)',
                scriptId: '0',
                url: '',
                lineNumber: -1,
                columnNumber: -1 },
             hitCount: 0,
             children: [ 2 ] },
             ...
    
          ]
        }
     }
    }

    Runtime域体验

    >>> Runtime.evaluate({expression:"1+1"})
    { result: { result: { type: 'number', value: 2, description: '2' } } }
    

    Schema域体验

    >>> Schema.getDomains()
    { result: 
    { domains: 
      [ { name: 'Runtime', version: '1.1' },
        { name: 'Debugger', version: '1.1' },
        { name: 'Profiler', version: '1.1' },
        { name: 'HeapProfiler', version: '1.1' },
        { name: 'Schema', version: '1.1' } ] } }

    体验事件处理

    scriptParsed是Debugger域提供的脚本解析事件

    >>> Debugger.scriptParsed(params=>params.url)
    { 'Debugger.scriptParsed': 'params=>params.url' }
    { 'Debugger.scriptParsed': '' }
    { 'Debugger.scriptParsed': '/Users/renbaogang/git/enzyme.node/node_modules/negotiator/lib/encoding.js' }

API

  1. module([options], [callback])

    基于chrome调试协议连接调试目标

    options object类型,具有如下属性:

    • host 默认localhost
    • port 默认9222
    • chooseTab 决定调试哪个tab。该参数可以为三种类型:
      • function 提供一个返回tab序号的函数
      • object 正如new 和 list返回的对象一样
      • string websocket url
        默认为一个函数,返回当前激活状态的tab的序号,如:function(tabs){return 0;}
    • protocol 协议描述符,默认由remote选项来定是否使用调试目标提供的协议描述符
    • remote 默认false,如果protocol设置了,该选项不会起作用

    callback
    如果callback是函数类型,则该函数在connect事件发生后会得到回调,并返回EventEmitter对象,如果不是,则返回Promise对象。

    EventEmitter对象支持如下事件:

    • connect
    function (chrome) {}

    当websocket连接建立后触发,chrome是Chome类型的实例。

    • disconnect

      function () {}

      关闭websocket连接时触发

    • error

      function (err) {}

      当通过http://host:port/json无法到达,或websocket连接无法建立时触发
      err,Error类型的错误对象

      使用样例,针对chrome浏览器:

    const Chrome = require('chrome-remote-interface');
    Chrome(function (chrome) {
    with (chrome) {
        Network.requestWillBeSent(function (params) {
            console.log(params.request.url);
        });
        Page.loadEventFired(function () {
            close();
        });
        Network.enable();
        Page.enable();
        once('ready', function () {
            Page.navigate({'url': 'https://github.com'});
        });
    }
    }).on('error', function (err) {
    console.error('Cannot connect to Chrome:', err);
    });
  2. module.Protocol([options],[callback])

    获取chrome调试协议描述符

    options object类型,具有如下属性:

    • host 默认localhost
    • port 默认9222
    • remote 默认false

    callback 回调函数,在获取到协议内容后调用,函数接收如下参数:

    • err Error一个错误对象,如果有错误的话
    • protocol 包含以下属性
      • remote 是否远程协议
      • descriptor chrome调试协议描述符

    使用样例:

    const Chrome = require('chrome-remote-interface');
    Chrome.Protocol(function (err, protocol) {
    if (!err) {
        console.log(JSON.stringify(protocol.descriptor, null, 4));
    }
    });
  3. module.List([options], [callback])

    获取所有的tabs,当然在node中只会有一个

    options object类型,具有如下属性:

    • host 默认localhost
    • port 默认9222
    • remote 默认false

    callback 回调函数,在获取到tabs内容后调用,函数接收如下参数:

    • err Error一个错误对象,如果有错误的话
    • tabs 获取到的tab数组

    使用样例:

    const Chrome = require('chrome-remote-interface');
    Chrome.List(function (err, tabs) {
    if (!err) {
        console.log(tabs);
    }
    });
  4. module.New([options], [callback])

    创建新的tab

    options object类型,具有如下属性:

    • host 默认localhost
    • port 默认9222
    • url 新tab加载的url 默认about:blank

    callback 回调函数,在新tab创建后调用,函数接收如下参数:

    • err Error一个错误对象,如果有错误的话
    • tab 新增的tab

    使用样例:

    const Chrome = require('chrome-remote-interface');
    Chrome.New(function (err, tab) {
    if (!err) {
        console.log(tab);
    }
    });
  5. module.Activate([options], [callback])

    激活指定tab

    options object类型,具有如下属性:

    • host 默认localhost
    • port 默认9222
    • id 目标tab的id

    callback 回调函数,在新tab创建后调用,函数接收如下参数:

    • err Error一个错误对象,如果有错误的话

    使用样例:

    const Chrome = require('chrome-remote-interface');
    Chrome.Activate({'id': 'CC46FBFA-3BDA-493B-B2E4-2BE6EB0D97EC'}, function (err) {
    if (!err) {
        console.log('success! tab is closing');
    }
    });
  6. module.Close([options], [callback])

    关闭指定tab

    options object类型,具有如下属性:

    • host 默认localhost
    • port 默认9222
    • id 目标tab的id

    callback 回调函数,在新tab创建后调用,函数接收如下参数:

    • err Error一个错误对象,如果有错误的话

    使用样例:

    const Chrome = require('chrome-remote-interface');
    Chrome.Close({'id': 'CC46FBFA-3BDA-493B-B2E4-2BE6EB0D97EC'}, function (err) {
    if (!err) {
        console.log('success! tab is closing');
    }
    });
  7. module.Version([options], [callback])

    获取版本信息

    options object类型,具有如下属性:

    • host 默认localhost
    • port 默认9222

    callback 回调函数,在新tab创建后调用,函数接收如下参数:

    • err Error一个错误对象,如果有错误的话
    • info json object

    使用样例:

    const Chrome = require('chrome-remote-interface');
    Chrome.Version(function (err, info) {
    if (!err) {
        console.log(info);
    }
    });
  8. Chrome 类

    支持的事件:

    • event

      在远程调试目标发送通知时触发,一般是远程对象执行了客户端提交的方法后

      function (message) {}

      message包含如下属性:

      • method 通知内容,方法名 如:’Network.requestWillBeSent’
      • params 参数内容

      使用样例:

      chrome.on('event', function (message) {
          if (message.method === 'Network.requestWillBeSent') {
              console.log(message.params);
          }   
      });
    • {method}

      调试目标通过websocket发送了一个指定方法名的通知

      function (params) {}

      使用样例:

      chrome.on('Network.requestWillBeSent', console.log);
    • ready

      每次没有调试命令等待调试目标返回时触发

      function () {}

      使用样例:

      只在Network和Page激活后加载一个url

      chrome.Network.enable();
      chrome.Page.enable();
      chrome.once('ready', function () {
          chrome.Page.navigate({'url': 'https://github.com'});
      });

    支持的方法

    • chrome.send(method, [params], [callback])

      发送一个调试命令

      method 命令名称
      params 参数
      callback 当远程对象对该命令发送一个应答后调用,函数具有以下参数:

      • error boolean 是否成功
      • response 如果error===true,返回一个error对象,{error:…},否则返回一个应答,{result:…}

      注意:在chrome调试规范里提到的id字段,在这里被内部管理不会暴露给用户

      使用样例:

      chrome.send('Page.navigate', {'url': 'https://github.com'}, console.log);
    • chrome.{domain}.{method}([params], [callback])

      是chrome.send(‘{domain}.{method}’, params, callback);的一种变形

      例如:

      chrome.Page.navigate({'url': 'https://github.com'}, console.log);
    • chrome.{domain}.{event}(callback)

      是chrome.on(‘{domain}.{event}’, callback)的变形

      例如:

      chrome.Network.requestWillBeSent(console.log);
    • chrome.close([callback])

      关闭与远程调试目标的连接
      callback会在websocket关闭成功后调用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值