`
hongtoushizi
  • 浏览: 378714 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

动态修改 NodeJS 程序中的变量值

阅读更多

转载自:http://code.oneapm.com/nodejs/2015/06/27/intereference/

动态修改 NodeJS 程序中的变量值

 

如果一个 NodeJS 进程正在运行,有办法修改程序中的变量值么?答案是:通过 V8 的 Debugger 接口可以!本文将详细介绍实现步骤。

启动一个 HTTP Server

用简单的 Hello World 做例子吧,不过略作修改。在 global 下放一个变量 message, 然后打印出来:

// message content will be modified !
global.message = "hello world!";

var server = require('http').createServer(function (req, res) {
  res.end(global.message);
}).listen(8001);

console.log('pid = %d', process.pid);

用命令启动 Server,此时,通过用浏览器访问 http://localhost:8001 可以看到网页内容是 hello world!。 接下来我们将尝试在不改变代码,不重启进程的情况下把 message 换成 "hello bugs!"。

使 Server 进程进入 Debug 模式

V8 引擎在实现的时候留了 Debugger 接口。 通过命令 node --debug-brk=5858 [filename] 可以启动一个脚本,并且立即进入 Debug 模式。

那么如果是已经运行着的 NodeJS 程序,可以进入 Debug 模式吗?也是可以的,在操作系统下给 NodeJS 的进程发一个 SIGUSR1 信号,可以让进程进入 Debug 模式。 进入 Debug 模式的进程会在本地启动一个 TCP Server 并且默认监听 5858 端口。

此时在另一个命令行窗口执行命令 node debug localhost:5858 就可以连接到 Debugger 调试端口, 并且可以使用很多常用的 Debug 命令,比如 c继续执行,s 步入, o步出等。

Debugger 协议

使用 node debug hostname:port 命令连接到进程进行 Debug 的方式比较简单,但是要完成一些高级的功能就会处处受限,因为它只封装了 Debugger 协议中 command 的一部分。 下面介绍一下这个简单的协议。

Client 和 Server 的通讯是通过 TCP 进行的。 DebugClient 第一次连接到 DebugServer 的时候会拿到一些 Header,比如 Node 版本, V8 版本等。后面紧跟着一个空的消息1

消息1

Type: connect\r\n
V8-Version: 3.28.71.19\r\n
Protocol-Version: 1\r\n
Embedding-Host: node v0.12.4\r\n
Content-Length: 0\r\n
\r\n

消息实体由 Header 和 Body 组成,消息1的 Body 为空,所以 Header 中对应的 Content-Length 为 0。而在下面这个例子里,Body 为一个单行的 JSON 字符串,这是由协议所规定的。

消息2

Content-Length: 46\r\n
\r\n
{"command":"version","type":"request","seq":1}

消息2的类型( type )是 request,代表这是 Client 发给 Server 的命令,其他的可能值是 responseevent 分别代表 Server 对 Client 的相应,和 Server 端发生的事件。

消息3

Content-Length: 137\r\n
\r\n
{"seq":1,"request_seq":1,"type":"response","command":"version","success":true,"body":{"V8Version":"3.28.71.19"},"refs":[],"running":true}

消息2是 Client 发送给 Server的,消息3是 Server 对 Client 的相应,那么如何判断消息3是不是消息2的结果呢?可以看到消息2中的 seq 值是1,而 消息3中的 request_seq 值是1。 Debugger 协议正是通过这两个值把异步返回的结果和请求一一对应起来的。

Debugger 协议就是这么的简单。

实例化一个 Debugger Client

了解了 Debugger 协议后,相信好奇心强的程序员已经跃跃欲试自己实现一个了。本着不重复发明轮子的原则开始在网上找实现,找了好久找到这个库 pDebug, 可惜这个库已经好久不更新了。后来通过阅读 node-inspector 的源码才发现,其实 NodeJS 自带了一个 Debugger 模块, 相关代码在 _debugger 模块里(源码),由于模块名是以 _ 开头的,所以网上找不到它的 API,好在代码注释写的非常详细,很快就能上手。

我们需要的正是这个模块下的 Client, 而 Client 其实是继承于 Socket 的.

var Client = require('_debugger').Client;
var client = new Client();

client.connect(5858);
client.on('ready', function () {
    // 连接成功
});

通过 Debugger 接口执行命令

接下来我们来看看如何修改这个 global 的变量,代码如下

function modifyTheMessage(newMessage) {
    var msg = {
        'command': 'evaluate',
        'arguments': {
            'expression': 'global.message="' + newMessage + '"',
            'global': true
        }
    };
    client.req(msg, function (err, body, res) {
        console.log('modified to %s', newMessage);
    });
}

client.req 方法封装了 type=request 消息类型 和 seq 自增的逻辑,因此在构造 msg JSON对象的时候不需要指明这两个属性。 我们要修改 message 其实就是在 JavaScript 调用的顶层执行 global.message=newMessage

总结

此时,再访问 http://localhost:8001 可以看到网页上显示的内容已经由 'hello world!' 变成了 'hello bugs!',是不是很神奇。

这种方式也带来了很多可能性:

  • 动态修改配置

线上的服务器不用重启就可以应用新的配置

  • 模块注入

通过其他任意语言编写的应用程序为已经运行的 NodeJS 进程注入新的模块

  • 性能监控

可以剥离用户线上代码对第三方性能监控模块的直接依赖

  • 错误监控

发生异常时,通过 Debugger 可以抓到发生错误的函数和行号,并且抓取各个调用栈中的每一个变量,即使是在闭包里

  • Chrome 调试

由于 Chrome 也是基于 V8 的,上述方法也可以用于 Chrome 相关的功能集成

关于

1. 本文相关的源码在: https://github.com/wyvernnot/interference_demo;

2. 如果你也对 Debugger 协议感兴趣,可以安装 oneapm-debugger 这个工具,它可以帮助你查看 Debug 过程中所有实际发送的数据。 oneapm-debugger

 

 

 
分享到:
评论

相关推荐

    nodejs调试

    在代码中设置断点,然后通过浏览器访问你的应用(http://localhost:3000),当请求到达断点时,程序会暂停,此时你可以检查变量状态,单步执行,或修改变量值继续运行。 八、高级调试技巧 1. 使用`console.log()`:...

    nodejs手册中文版

    - 使用 npm (Node Package Manager) 管理 Node.js 应用程序中的依赖关系。 - 通过 `npm install <module>` 命令安装模块到项目的 `node_modules` 文件夹中。 - 使用 `npm uninstall <module>` 卸载模块。 - `npm ...

    NodeJS文档

    ### NodeJS文档知识点详解 #### 概要 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。它使开发人员能够使用 JavaScript 编写服务端应用程序。Node.js 利用非阻塞 I/O 和事件驱动架构来提供高效、可...

    nodejs在windows下的安装配置

    - 将 Node.js 的安装目录(例如 `C:\Program Files\nodejs\`)添加到变量值的末尾,各条目之间用分号(;)隔开。 - **验证安装**: - 打开命令提示符窗口(cmd.exe),输入`node -v`查看当前安装的 Node.js 版本。...

    Windows系统nodejs安装及环境配置步骤

    - 将Node.js的安装路径(如`D:\Program Files\nodejs`)添加到变量值中。 #### 三、注意事项 - **管理员权限**: 安装和配置过程中,请确保使用管理员权限运行命令提示符或PowerShell,以避免权限问题导致的错误。...

    nodejs安装及环境配置.docx

    - 新建系统变量 `NODE_PATH`,值为 `D:\Program Files\nodejs\node_global\node_modules`。 - 编辑用户变量 `Path`,将 `C:\Users\用户名\AppData\Roaming\npm` 更改为 `D:\Program Files\nodejs\node_global`。 ...

    nodejs安装及环境配置.doc

    - 同样在 “系统变量” 区域点击 “新建”,输入变量名 “NODE_HOME” 和变量值(即 Node.js 的安装路径)。 - 确认保存后退出所有对话框。 #### 五、验证安装 1. **打开命令提示符**: - 打开命令提示符(CMD)...

    Atom-xatom-debug-nodejs,用于xatom调试的nodejs调试器插件。对xatom的贡献.zip

    5. **变量查看**:在调试会话中,插件会显示所有局部和全局变量的值,帮助你追踪和理解代码状态。 6. **表达式求值**:在运行时,你可以即时计算和查看任何表达式的值,无需离开当前工作区。 7. **运行和停止控制*...

    NodeJS父进程与子进程资源共享原理与实现方法

    由于每个进程都有自己的内存空间,直接修改全局变量并不能使所有进程都看到改变,如`globalDataError`变量在父进程和子进程间就是独立的,无法实现真正的共享。 正确的资源共享方法是通过监听`message`事件和`send`...

    nodejs安装及环境配置.pdf

    - 在“用户变量”区域,找到名为 `Path` 的变量,点击“编辑”,在变量值的末尾添加 `;Node.js 安装路径\node_global`(注意前面的分号)。 ##### 3. 测试配置 - **安装全局模块**: - 在命令行中尝试安装一个...

    nodejs小书(中文版)

    此外,本书采用的是Creative Commons的姓名标示-非商业性授权(BY-NC)许可证,允许读者复制、散布和修改书中的内容,但禁止将书用于商业目的。读者可以通过相关网链获取完整的授权条款。最后,本书由Node.js Taiwan...

    Node.js安装及环境配置详细教程-从0到1教你学会nodejs安装及环境配置

    - 变量值:`C:\Program Files\nodejs\node_global\node_modules`(根据实际情况替换路径) - 创建完成后,手动在指定路径下创建`node_modules`文件夹。 3. **修改PATH环境变量**: - 选中用户变量中的`Path`,...

    nodejs安装及环境配置.rar

    例如,在Windows上,可以在系统属性的环境变量中新增一个变量名为`NODE_PATH`,值为你的自定义路径。 3. 配置npm:npm的配置文件位于用户目录下的`.npmrc`文件,可以通过`npm config list`查看当前配置。可以使用`...

    nodejs自动批量翻译中文到其它语言.pdf

    - 谷歌翻译接口通过改变页面上的源语言输入框的值来提交翻译请求,然后从目标语言的输出框中获取翻译结果。 这个方法虽然有效,但存在一些潜在问题和优化空间: 1. 性能:由于是逐个文件逐行翻译,效率可能较低,...

    详解Windows下安装Nodejs步骤

    - 修改用户变量中的`PATH`,将`C:\nodejs\node_global`添加到路径列表中。 5. **测试配置**:安装一个模块,如Web应用开发框架Express,验证配置是否正确。在命令行中输入`npm install -g express`全局安装Express...

    浅析 NodeJs 的几种文件路径

    这意味着如果你在不同的目录下启动应用程序,`process.cwd()`会返回不同的值。 4. `./` 或 `../`: 这些是相对路径,用于表示当前目录(`.`)或上一级目录(`..`)。在Node.js中,相对路径的解析依赖于启动脚本的...

Global site tag (gtag.js) - Google Analytics