這篇文章將為大家詳細(xì)講解有關(guān)如何實(shí)現(xiàn)Node的Inspector代理,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
創(chuàng)新互聯(lián)公司于2013年創(chuàng)立,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都做網(wǎng)站、網(wǎng)站建設(shè)網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢想脫穎而出為使命,1280元沾益做網(wǎng)站,已為上家服務(wù),為沾益各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:028-86922220
背景
平時(shí)做 node 開發(fā)的時(shí)候,通過 node inspector 來進(jìn)行斷點(diǎn)調(diào)試是一個(gè)很常用的 debug 方式。但是有幾個(gè)問題會(huì)導(dǎo)致我們的調(diào)試效率降低。
問題一:當(dāng)使用 vscode 進(jìn)行斷點(diǎn)調(diào)試時(shí),如果應(yīng)用是通過 cluster 啟動(dòng)的 inspector,那么每次當(dāng) worker 掛了重啟后,inspector 的端口都會(huì)自增。雖然在 node8.x 版本中可以指定 inspectPort 固定調(diào)試端口,但是在 node6.x 中是不支持的。這樣會(huì)導(dǎo)致每次 worker 重啟了就得在 vscode 中重新指定調(diào)試端口。
問題二:當(dāng)使用 devtools 調(diào)試的時(shí)候,每次調(diào)試都需要拷貝 devtools 鏈接到 chrome 上調(diào)試,而上面說的端口變更問題則會(huì)導(dǎo)致 devtools 的鏈接變更,除此之外,每次重新啟動(dòng) inspector 也會(huì)導(dǎo)致 devtools 的鏈接變更,因?yàn)?websocket id 變了。
而把上面的兩個(gè)問題簡化一下就是:
在 vscode 中調(diào)試,在 inspector 端口變更或者 websocket id 變更后能夠重連。
在 devtools 中調(diào)試,在 inspector 端口變更或者 websocket id 變更后能夠重連。
解決方案
目前業(yè)界已經(jīng)有解決方案就是 chrome 插件 Node Inspector Manager(Nim)
,不過這個(gè)只能解決在同個(gè) inspector 端口下的應(yīng)用重啟后鏈接更改的問題,卻無法解決 cluster 啟動(dòng)導(dǎo)致的端口自增問題,除非在 Nim 中提前指定好多個(gè)端口,再者 Nim 是 chrome 上的插件,對(duì)于在 vscode 中的調(diào)試卻無能為力了。
所以最佳的解決方案自然是使用 node 來做 inspector 代理,解決方案如下:
對(duì)于第一個(gè)問題,在 vscode 上,它是會(huì)自己去調(diào)用 /json 接口獲取最新的 websocket id,然后使用新的 websocket id 連接到 node inspector 服務(wù)上。因此解決方法就是實(shí)現(xiàn)一個(gè) tcp 代理功能做數(shù)據(jù)轉(zhuǎn)發(fā)即可。
對(duì)于第二個(gè)問題,由于 devtools 是不會(huì)自動(dòng)去獲取新的 websocket id 的,所以我們需要做動(dòng)態(tài)替換,所以解決方案就是代理服務(wù)去 /json 獲取 websocket id,然后在 websocket 握手的時(shí)候?qū)?websocket id 進(jìn)行動(dòng)態(tài)替換到請(qǐng)求頭上。
畫了一張流程圖:
實(shí)現(xiàn)步驟
一、Tcp 代理
首先,先實(shí)現(xiàn)一個(gè) tcp 代理的功能,其實(shí)很簡單,就是通過 node 的 net 模塊創(chuàng)建一個(gè)代理端口的 Tcp Server,然后當(dāng)有連接過來的時(shí)候,再創(chuàng)建一個(gè)連接到目標(biāo)端口即可,然后就可以進(jìn)行數(shù)據(jù)的轉(zhuǎn)發(fā)了。
簡易的實(shí)現(xiàn)如下:
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); }); // 如果真要應(yīng)用到業(yè)務(wù)中,還得監(jiān)聽一下錯(cuò)誤/關(guān)閉事件,在連接關(guān)閉時(shí)即時(shí)銷毀創(chuàng)建的 socket。 }).listen(proxyPort);
上面實(shí)現(xiàn)了比較簡單的一個(gè)代理服務(wù),通過 pipe 方法將兩個(gè)服務(wù)的數(shù)據(jù)連通起來。client 有數(shù)據(jù)的時(shí)候會(huì)被轉(zhuǎn)發(fā)到 server 中,server 有數(shù)據(jù)的時(shí)候也會(huì)轉(zhuǎn)發(fā)到 client 中。
當(dāng)完成這個(gè) Tcp 代理功能之后,就已經(jīng)可以實(shí)現(xiàn) vscode 的調(diào)試需求了,在 vscode 中項(xiàng)目下 launch.json 中指定端口為代理端口,在 configurations 中添加配置
{ "type": "node", "request": "attach", "name": "Attach", "protocol": "inspector", "restart": true, "port": 9229 }
那么當(dāng)應(yīng)用重啟,或者更換 inspect 的端口,vscode 都能自動(dòng)重新通過代理端口 attach 到你的應(yīng)用。
二、獲取 websocketId
這一步開始,就是為了解決 devtools 鏈接不變的情況下能夠重新 attach 的問題了,在啟動(dòng) node inspector server 的時(shí)候,inspector 服務(wù)還提供了一個(gè) /json 的 http 接口用來獲取 websocket id。
這個(gè)就相當(dāng)簡單了,直接發(fā)個(gè) http 請(qǐng)求到目標(biāo)端口的 /json,就可以獲取到數(shù)據(jù)了:
[ { 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' } ]
上面數(shù)據(jù)中的 id 字段,就是我們需要的 websocket id 了。
三、Inspector 代理
拿到了 websocket id 后,就可以在 tcp 代理中做 websocket id 的動(dòng)態(tài)替換了,首先我們需要固定鏈接,因此先定一個(gè)代理鏈接,比如我的代理服務(wù)端口是 9229,那么 chrome devtools 的代理鏈接就是:
chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9229/__ws_proxy__
上面除了最后面的 ws=127.0.0.1:9229/__ws_proxy__
其他都是固定的,而最后這個(gè)也一眼就可以看出來是 websocket 的鏈接。其中 __ws_proxy__
則是用來占位的,用于在 chrome devtools 向這個(gè)代理鏈接發(fā)起 websocket 握手請(qǐng)求的時(shí)候,將 __ws_proxy__
替換成 websocket id 然后轉(zhuǎn)發(fā)到 node 的 inspector 服務(wù)上。
對(duì)上面的 tcp 代理中的 pipe
邏輯的代碼做一些小修改即可。
const through = require('through3'); ... 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); ...
通過 through3 創(chuàng)建一個(gè) transform 流來對(duì)傳輸?shù)臄?shù)據(jù)進(jìn)行一下更改。
簡單判斷一下 chunk 的頭三個(gè)字節(jié)是否為GET
,如果是 GET 說明這可能是個(gè) http 請(qǐng)求,也就可能是 websocket 的協(xié)議升級(jí)請(qǐng)求。把請(qǐng)求頭打印出來就是這個(gè)樣子的:
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替換成對(duì)應(yīng)的 websocketId,然后轉(zhuǎn)發(fā)到 node 的 inspector server 上,即可完成 websocket 的握手,接下來的 websocket 通信就不需要對(duì)數(shù)據(jù)做處理,直接轉(zhuǎn)發(fā)即可。
接下來就算各種重啟應(yīng)用,或者更換 inspector 的端口,都不需要更換 debug 鏈接,只需要再 inspector server 重啟的時(shí)候,在下圖的彈窗中
點(diǎn)擊一下 Reconnect DevTools 即可恢復(fù) debug。
關(guān)于“如何實(shí)現(xiàn)Node的Inspector代理”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
分享題目:如何實(shí)現(xiàn)Node的Inspector代理
地址分享:http://bm7419.com/article10/ijphgo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站策劃、、建站公司、定制開發(fā)、動(dòng)態(tài)網(wǎng)站、標(biāo)簽優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)