首頁  >  文章  >  web前端  >  Node Inspector 代理實作實例教學

Node Inspector 代理實作實例教學

小云云
小云云原創
2018-01-09 10:29:581514瀏覽

本文主要介紹了淺談Node Inspector 代理實現,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟著小編過來看看吧,希望能幫助大家。

背景

平常做 node 開發的時候,透過 node inspector 來進行斷點偵錯是一個很常用的 debug 方式。但是有幾個問題會導致我們的調試效率降低。

問題一:當使用 vscode 進行斷點偵錯時,如果應用程式是透過 cluster 啟動的 inspector,那麼每次當 worker 掛了重啟後,inspector 的連接埠都會自增。雖然在 node8.x 版本中可以指定 inspectPort 固定偵錯端口,但在 node6.x 中是不支援的。這樣會導致每次 worker 重啟了就得在 vscode 中重新指定調試端口。

問題二:當使用devtools 調試的時候,每次調試都需要拷貝devtools 鏈接到chrome 上調試,而上面說的端口變更問題則會導致devtools 的鏈接變更,除此之外,每次重新啟動inspector 也會導致devtools 的連結變更,因為websocket id 改變了。

而把上面的兩個問題簡化一下就是:

  • 在 vscode 中調試,在 inspector 連接埠變更或 websocket id 變更後能夠重連。

  • 在 devtools 中除錯,在 inspector 連接埠變更或 websocket id 變更後能夠重連。

解決方案

目前業界已經有解決方案就是chrome 外掛Node Inspector Manager(Nim) ,不過這個只能解決在同個inspector 連接埠下的應用程式重啟後連結更改的問題,卻無法解決cluster 啟動導致的端口自增問題,除非在Nim 中提前指定好多個端口,再者Nim 是chrome 上的插件,對於在vscode 中的調試卻無能為力了。

所以最佳的解決方案自然是使用node 來做inspector 代理,解決方案如下:

對於第一個問題,在vscode 上,它是會自己去調用/json 接口取得最新的websocket id,然後使用新的websocket id 連接到node inspector 服務。因此解決方法就是實作一個 tcp 代理功能做資料轉送即可。

對於第二個問題,由於devtools 是不會自動去取得新的websocket id 的,所以我們需要做動態替換,所以解決方案就是代理服務去/json 取得websocket id,然後在websocket 握手的時候將websocket id 進行動態替換到請求頭上。

畫了一張流程圖:

實作步驟

一、Tcp 代理

首先,先實現一個tcp 代理的功能,其實很簡單,就是透過node 的net 模組建立一個代理埠的Tcp Server,然後當有連接過來的時候,再建立一個連接到目標連接埠即可,然後就可以進行資料的轉送了。

簡易的實作如下:

const net = require('net');
const proxyPort = 9229;
const forwardPort = 5858;

net.createServer(client => {
 const server = net.connect({
  host: '127.0.0.1',
  port: forwardPort,
 }, () => {
  client.pipe(server).pipe(client);
 });
 // 如果真要应用到业务中,还得监听一下错误/关闭事件,在连接关闭时即时销毁创建的 socket。
}).listen(proxyPort);

上面實作了比較簡單的一個代理服務,透過 pipe 方法將兩個服務的資料連通起來。 client 有資料的時候會被轉送到 server 中,server 有資料的時候也會轉送到 client 中。

當完成這個Tcp 代理功能之後,就已經可以實現vscode 的調試需求了,在vscode 中項目下launch.json 中指定端口為代理端口,在configurations 中添加配置

{
 "type": "node",
 "request": "attach",
 "name": "Attach",
 "protocol": "inspector",
 "restart": true,
 "port": 9229
}

那麼當應用程式重啟,或是更換inspect 的端口,vscode 都能自動重新通過代理端口attach 到你的應用。

二、取得websocketId

這一步開始,就是為了解決devtools 連結不變的情況下能夠重新attach 的問題了,在啟動node inspector server 的時候,inspector 服務也提供了一個/json 的http 介面用來取得websocket id。

這個就相當簡單了,直接發個http 請求到目標端口的/json,就可以獲取到數據了:

[ { description: 'node.js instance',
  devtoolsFrontendUrl: '...',
  faviconUrl: 'https://nodejs.org/static/favicon.ico',
  id: 'e7ef6313-1ce0-4b07-b690-d3cf5274d8b0',
  title: '/Users/wanghx/Workspace/larva-team/vscode-log/index.js',
  type: 'node',
  url: 'file:///Users/wanghx/Workspace/larva-team/vscode-log/index.js',
  webSocketDebuggerUrl: 'ws://127.0.0.1:5858/e7ef6313-1ce0-4b07-b690-d3cf5274d8b0' } ]

上面數據中的id 字段,就是我們需要的websocket id 了。

三、Inspector 代理

拿到了websocket id 後,就可以在tcp 代理中做websocket id 的動態替換了,首先我們需要固定鏈接,因此先定一個代理鏈接,比如我的代理服務埠是9229,那麼chrome devtools 的代理連結就是:

chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9229/__ws_proxyxy

##上面除了最後面的ws=127.0.0.1:9229/__ws_proxy__ 其他都是固定的,而最後這個也一眼就可以看出來是websocket 的連結。其中 __ws_proxy__則是用來佔位的,用於在 chrome devtools 向這個代理鏈接發起 websocket 握手請求的時候,將 __ws_proxy__ 替換成 websocket id 然後轉發到 node 的 inspector 服務上。

對上面的 tcp 代理中的 pipe 邏輯的程式碼做一些小修改即可。

const through = require('through2');
...

client
   .pipe(through.obj((chunk, enc, done) => {
    if (chunk[0] === 0x47 && chunk[1] === 0x45 && chunk[2] === 0x54) {
     const content = chunk.toString();
     if (content.includes('__ws_proxy__')) {
      return done(null, Buffer.from(content.replace('__ws_proxy__', websocketId)));
     }
    }
    done(null, chunk);
   }))
   .pipe(server)
   .pipe(client);
...
透過 through2 建立一個 transform 流來對傳輸的資料進行一下更改。

简单判断一下 chunk 的头三个字节是否为GET,如果是 GET 说明这可能是个 http 请求,也就可能是 websocket 的协议升级请求。把请求头打印出来就是这个样子的:

GET /__ws_proxy__ HTTP/1.1
Host: 127.0.0.1:9229
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: chrome-devtools://devtools
Sec-WebSocket-Version: 13
...

然后将其中的路径/__ws_proxy替换成对应的 websocketId,然后转发到 node 的 inspector server 上,即可完成 websocket 的握手,接下来的 websocket 通信就不需要对数据做处理,直接转发即可。

接下来就算各种重启应用,或者更换 inspector 的端口,都不需要更换 debug 链接,只需要再 inspector server 重启的时候,在下图的弹窗中

点击一下 Reconnect DevTools 即可恢复 debug。

相关推荐:

Web Inspector:关于在 Sublime Text 中调试Js的介绍_基础知识

Node.js设计模式使用流进行编码

NodeJs之数据库异常处理详解

以上是Node Inspector 代理實作實例教學的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn