教你開發whistle插件
- 2019 年 12 月 4 日
- 筆記
whistle介紹
whistle是一款用Node實現的跨平台的Web調試代理工具,支援查看修改http(s)、Websocket連接的請求和響應內容。IMWEB團隊avenwu作品。github地址:https://github.com/avwo/whistle
whistle安裝啟動
1、安裝whistle
npm install -g whistle
2、 啟動whistle
w2 start // 啟動whistle w2 restart // 重啟whsitle w2 run // 調試模式啟動whistle
3、 在瀏覽器中訪問
(1)域名訪問 http://local.whistlejs.com/ (2)通過ip+埠來訪問,例如: http://127.0.0.1:8899
whistle插件開發
現在想做一個基於whistle的查看請求參數的插件,並將參數以表格的形式展示在頁面上
插件命名規範
whistle插件本身就是一個普通的Node模組,只是名字要按照whistle.xxx的形式命名,其中xxx指插件的名稱且只能包含小寫字母、數字、_、-四種字元,如:whistle.tdw,而xxx就是擴展的協議,可以直接在Rules裡面配置使用
插件目錄結構
whistle.tdw |__ package.json |__ rules.txt |__ index.js |__ lib |__ ui-server.js |__ plugin-server.js
index.js提供whistle暴露給開發者的介面
// index.js var initPluginServer = require('./lib/plugin-server'); var initUIServer = require('./lib/ui-server'); exports.statsServer = function(server, options) { initPluginServer(server, options); }; exports.uiServer = function(server, options) { initUIServer(server, options); };
statsServer : 處理請求的server,可以做請求合併等,返回的數據就是請求的響應數據, 如上: options 包含一些自定義的頭部欄位名稱及配置資訊
{ name: // 插件的名稱, RULE_VALUE_HEADER: // 存儲配置的規則值的請求頭欄位, SSL_FLAG_HEADER: // 判斷是否為HTTPS請求的請求頭欄位, FULL_URL_HEADER: // 存儲請求完整url的請求頭欄位, REAL_URL_HEADER: // 存儲配置映射到url的請求頭欄位, NEXT_RULE_HEADER: // 存儲配置的下個規則(第一規則為插件)的請求頭欄位, REQ_ID_HEADER: // 請求的id,可以用於區分響應和請求是否同一個, DATA_ID_HEADER: // 數據包對應的id,不一定存在, STATUS_CODE_HEADER: // 配置的響應狀態碼, LOCAL_HOST_HEADER: // 配置的hosts, HOST_PORT_HEADER: // 配置的埠, METHOD_HEADER: // 請求方法, debugMode: // 是否是通過w2 run啟動的, config: // 包括whistle的埠號port等一系列whistle的配置, storage: //提供本地存儲的介面,用法參 考:https://github.com/avwo/whistle/blob/master/lib/rules/util.js }
server是是whistle傳給插件的http.Server對象,開發者通過監聽server的相關事件處理whistle轉發過來的請求
uiServer: local.whistlejs.com/whistle.xxx下的請求都會直接訪問該server,可用於後台管理介面
插件調試
把本地node模組link到全局目錄:
npm link 開啟whistle的調試模式 $ w2 run 這樣whistle會自動載入改插件,如果插件有程式碼更新,需要觸發修改package.json這個文件,比如加個空格,或者直接加個欄位,每次修改下這個欄位,whistle會檢查package.json是否有更改,如果更改的話會自動重啟。
具體實現
// lib/plugin-server.js module.exports = function(server, options) { FULL_URL_HEADER = options.FULL_URL_HEADER; SSL_FLAG_HEADER = options.SSL_FLAG_HEADER; server.on('request', app); initHttpServer(app); }; function initHttpServer(app) { app.use(function(req, res, next) { dataEvent.emit('data', {query: req.headers}); res.end(''); }); }
打開whistle,訪問https://ke.qq.com , 在network介面上能看到很多的請求

通過statsServer介面,我們能獲取這些請求。這裡通過事件將獲取到的請求傳遞到uiserver中
// ui-server.js module.exports = function(server, options) { FULL_URL_HEADER = options.FULL_URL_HEADER; server.on('request', app); var io = require('socket.io')(server); initHttpServer(app); initWSServer(io); }; function initHttpServer(app) { app.get('/', function(req, res) { res.sendFile(path.join(htdocs, 'index.html')); }); app.get('/js/*', function(req, res) { res.sendFile(path.join(htdocs, 'js/index.js')); }); } function initWSServer(io) { io.on('connection', function (socket) { dataEvent.on('data', function(data) { socket.emit('data', getUrl(data)); }); }); }
在瀏覽器中訪問http://local.whistlejs.com/whistle.tdw ,請求會直接訪問uiServer ,如上, uiServer處理請求,返回給瀏覽器相關的資源文件,展示介面。現在想實時的在頁面上展示請求的鏈接參數,選擇socket.io來實現 。 服務端與客戶端建立鏈接,將statsServer傳輸過來的數據,推給瀏覽器展示。
客戶端js:
// js/index.js var io = require('socket.io-client'); var socket = io({ path: '/whistle.tdw/socket.io' }); socket.on('data', function(data) { var list = self.state.list; list.unshift(decodeReport(data)); self.setState({ list: list }); });
結果頁面展示

插件發布
同發布正常的node模組,模組編寫完畢, 通過 npm publish 發布