node调试协议
引言
研究node调试协议(实际上是chrome调试协议)对设计和实现自己的node远程调试工具来说至关重要,它不仅被用在chrome的开发工具中,也可以用它来实现自己的web ide产品,比如调试node中运行的javascript代码。
协议的版本
chrome调试协议是调试客户端和调试目标进行调试交互的规范,该协议通过json格式的文档protocol.json给出。
目前协议稳定版本是1.2,针对不同的运行环境protocol.json分为两个不同的协议内容,一种是提供给chrome浏览器的,一种是提供给基于V8 javascript引擎的运行环境,如node。
通过https://chromedevtools.github.io/debugger-protocol-viewer/ 可以了解协议的相关信息。
目前,提供给浏览器的协议描述在:
https://chromedevtools.github.io/debugger-protocol-viewer/1-2/。
提供给基于V8运行环境的在:
https://chromedevtools.github.io/debugger-protocol-viewer/v8/。
为了调试node应用程序,所以我们比较关注后者。
node6.3.0发布了一个v8-inspector重大变更,支持--inspect启动标识,因此从该版本开始,可以基于chrome调试协议去调试node了。
查看node所支持的协议版本
通过如下命令启动node应用程序,如下所示:(app.js是你要运行的应用程序的入口程序)
node --inspect=9222 app.js
在浏览器中输入url:
http://127.0.0.1:9222/json/version
将得到类似如下返回内容:
node6.3
[ { "Browser": "node.js/v6.3.0", "Protocol-Version": "1.1", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36(KHTML, like Gecko) Chrome/45.0.2446.0 Safari/537.36", "WebKit-Version": "537.36 (@198122)"} ]
node7.0
[ {
"Browser": "node.js/v7.0.0",
"Protocol-Version": "1.1"
} ]
从返回内容来看协议版本为1.1。
最好升级node到最新的稳定版,因为在node6.8中发布了一个变更,可以通过url:
http://127.0.0.1:9222/json/protocol获取到json格式的具体协议内容。
类似如下内容:
{
"version": { "major": "1", "minor": "1" },
"domains": [
......
]
}
协议内容
调试协议分为六个domain,分别为Schema、Runtime、Debugger、Console、Profiler、HeapProfiler。我们这里主要关注Debugger。
Debugger向开发者提供了调试javascript的的能力,如java调试一样,可以设置断点、跟踪线程栈、进行step。
Debugger域
方法
-
enable()
针对当前页面启动调试能力,客户端在调试前必须调用该方法启动调试能力,并在得到该方法的返回后才能正式进入调试
-
disable()
针对当前页面禁用调试能力
-
setBreakpointsActive(active:boolean)
激活当前页面的所有断点
-
setSkipAllPauses(skip:boolean)
使当前页不会被任何暂停事件所中断,如断点、异常、dom异常等
-
setBreakpointByUrl
参数:
lineNumber:integer
url:string optional 设置断点的目标脚本url
urlRegex:string optional 匹配正则表达式的url
columnNumber:integer optional
condition:string optional 设置断点条件返回值:
{breakpointId:BreakpointId,locations:[Location]}在给定url的javascript文件中设置断点。一旦该命令得到执行,将返回断点id,和应用该断点的文件位置。url和urlRegex必须得设置一个。
-
setBreakpoint
参数:
location:Location
condition:string返回:
{breakpointId:BreakpointId,actualLocation:Location}在给定的Location处设置断点
-
removeBreakpoint(breakpointId:BreakpointId)
删除断点
-
continueToLocation(location:Location)
继续执行,直到到达目标位置
stepOver()
stepInto()
stepOut()
pause()
resume()
-
searchInContent
参数:
scriptId:Runtime.ScriptId 搜索目标脚本的id
query:string 搜索内容
caseSensitive:boolean optional 是否大小写敏感
isRegex:boolean optional 是否使用正则表达式返回:
{result:[SearchMatch]}在指定目标脚本里搜索字符串,该方法属于体验性方法
-
setScriptSource
参数:
scriptId:Runtime.ScriptId
scriptSource:string 新的脚本内容
dryRun:boolean optional 如果设置为true,改变不会被真正被应用。经常用来获取结果而并不真正去改变代码返回:
{
callFrames:[CallFrame], //optional 如果编辑发生了,返回新的栈帧
stackChanged:boolean, //optional 当前调用栈是否被改变
asyncStackTrace:Runtime.StackTrace //optional 异步的stack trace,如果有的话
exceptionDetails:Runtime.ExceptionDetails //optional 异常信息,如果有的话
}编辑脚本内容
-
restartFrame
参数:
callFrameId:CallFrameId 栈帧id返回:
{
callFrames:[CallFrame] //新的stack trace
asyncStackTrace:Runtime.StackTrace
}重新从某一栈帧开始执行
-
getScriptSource(scriptId:Runtime.ScriptId)
返回:
{
scriptSource:string
}获取脚本内容
-
setPauseOnExceptions
参数:
state:string 只能设置三个值:none, uncaught, all.定义在什么异常情况下暂定,默认是none。all为任何异常都暂停。
-
evaluateOnCallFrame
参数:
callFrameId:CallFrameId
expression:string 表达式内容
objectGroup:string optional 将结果放在哪个分组下
includeCommandLineAPI:boolean optional 指定表达式是否应该存在命令行api,默认false
silent:boolean optional 在静默状态下,表达式评估异常不会报告且不会造成暂定
returnByValue:boolean optional 是否期望返回结果是json对象
generatePreview:boolean optional 是否生成结果预览,体验性参数返回:
{
result:Runtime.RemoteObject
exceptionDetails:Runtime.ExceptionDetails//optional
}在指定栈帧评估表达式
-
setVariableValue
参数:
scopeNumber:integer 域序号,基于0。只运行local、closure、catch域。
variableName:string 变量名
newValue:Runtime.CallArgument 新的变量值
callFrameId:CallFrameId指定栈帧上设置某变量的值
-
setAsyncCallStackDepth
参数:
maxDepth:integer 异步调用栈的最大深度,,默认为0,不去收集异步调用栈禁用或启用异步调用栈的跟踪
-
setBlackboxPatterns
体验性 略
-
setBlackboxedRanges
体验性 略
事件
-
scriptParsed
虚拟机解析脚本时触发
参数:
scriptId:Runtime.ScriptId
url:string
startLine:integer
startColumn:integer
endLine:integer
endColumn:integer
executionContextId:Runtime.ExecutionContextId 脚本的执行上下文
hash:string
executionContextAuxData:object optional
isLiveEdit:boolean optional 脚本是否来自动态改变的内容。体验性。
sourceMapURL:string optional source map的url
hasSourceURL:boolean optional 脚本是否存在source url -
scriptFailedToParse
虚拟机解析脚本失败时触发
参数:
scriptId:Runtime.ScriptId
url:string
startLine:integer
startColumn:integer
endLine:integer
endColumn:integer
executionContextId:Runtime.ExecutionContextId 脚本的执行上下文
hash:string
executionContextAuxData:object optional
sourceMapURL:string optional source map的url
hasSourceURL:boolean optional 脚本是否存在source url -
breakpointResolved
当一个断点在某脚本的目标位置得带应用时触发
参数:
breakpointId:BreakpointId
location:Location -
paused
当虚拟因异常或断点或其它缘由暂停时
参数:
callFrames: [ CallFrame ] 虚拟机停止在哪个栈
reason:string 原因(包括XHR, DOM, EventListener, exception, assert, debugCommand, promiseRejection, other).
data:object optional 辅助属性
hitBreakpoints:[string] optional hit到的断点id
asyncStackTrace:Runtime.StackTrace optional -
resumed
虚拟机恢复运行时触发
类型
-
BreakpointId
断点id
string -
CallFrameId
调用栈id
string -
Location
代码位置
object
属性:
scriptId:Runtime.ScriptId
lineNumber:integer
columnNumber:integer optional -
CallFrame
栈帧
object
属性:
callFrameId:CallFrameId
functionName:string 函数名
functionLocation:Location optional 体验性
location:Location
scopeChain:[Scope] 该帧的调用域链
this:Runtime.RemoteObject 该帧的调用者
returnValue:Runtime.RemoteObject optional 如果该帧处于函数返回点将得到返回值 -
Scope
执行域
object
属性:
type:string 包括:global, local, with, closure, catch, block, script
object:Runtime.RemoteObject 代表该执行域的对象,对global和with域来说代表真正的对象,对于其他域只是该域的描述,包括了域里的属性和变量
name:string optional
startLocation:Location
endLocation:Location -
SearchMatch
搜索匹配结果
object
属性:
lineNumber:number 所在行
lineContent:string 匹配的内容