從手寫到 ADB 配合 Whistle 搗鼓前后端極度舒適的調試環境
前因
相信每一位前端程序員,在日常編寫代碼中,或多或少都會碰到前端三題:
㈠ 有沒有便捷的 H5 頁面抓包和模擬假數據方法?
㈡ 在公司網絡限制下如何做到手機直連電腦服務,而不是通過費時費力的流水線打包訪問測試服務器?
㈢ 學習業界優秀的技術方案時,能不能直接“試”著“改”代碼,所見即所得地剖(pōu)析測試?
“工欲善其事,必先利其器”,這個問題一直困擾著渴望“高效工作,健康生活”的我。那么,有沒有一種既要手機直連電腦服務高效調試,又要沒有代碼倉庫仍能想怎么改就怎么改,還要操作簡單的前后端調試解決方案?
看見
一個偶然的機會,我發現同事子力在使用 ADB(Android Debug Bridge) 端口轉發命令(adb reverse tcp:8081 tcp:8081),通過數據線使手機直連電腦服務,他這么做主要是為了便于控制影響因子,方便二分法排查網頁性能影響因素。
我當時眼睛一亮,這不就是我一直在苦苦尋找的手機直連電腦解決方案么?
其實我也是 Android 起家,不禁讓我想到 ReactNative 開發時就用過這個命令來啟動電腦服務供手機開發調試,不過當時不求甚解,只是把這個命令當工具用,導致現在的我也成了工具...
再舉一反三地想一想, Chrome DevTools 的設備檢查功能(chrome://inspect/#devices)和 Vysor 的電腦遠程控制投影手機功能都是類似手機直連電腦實時預覽的解決方案。
圖片來源: Remote debug Android devices
話說,高手的世界像星空,你看得見,卻看不懂。但至此,已經看到更大世界的我,思如泉涌,也想試試能不能由淺入深地看懂。
由淺
先把野獸般的想象力收一收,由淺入深地想想,問題是什么,我要干啥?不就是前后端調試環境么?要是我能手寫一個簡單后端服務,自己和自己聯調,那感覺,倍爽。
手寫前后端
先寫一個包含網絡請求的簡單 H5 頁面。
接下來使用備受青睞的 Express Web 框架 (極簡風格且開源),搭一個后端服務。可以直接上網 Ctrl + C 和 Ctrl + V,我參考《一杯茶的時間,上手 Express 框架》,復制過來改一下,根據 URL 路徑分別返回 Html 主文檔和 json 數據。
因為本地沒有 express 包,需要運行 npm install express 手動安裝依賴。為了避免國內安裝速度太慢,建議先運行 npm config set registry http://registry.npm.taobao.org 設置國內鏡像。最后運行 node simple-html-and-json-server.js 啟動本地服務。
讓我們來看看瀏覽器打開 http://localhost:3000/ 效果。
可以,整體跑起來了,hello.json 數據請求失敗,意料之中,線上本來就沒有 http://sheng.shuqiang.com/hello.json 服務鏈接,把線上域名改成本地試試 http://localhost:3000/hello.json。
漂亮!!!至此,本地搭建的前后端環境已經成功了,問題 ㈠ 已拿下。代碼在手,天下我有,想咋地咋地,模擬假數據(Mock)自然不在話下。是不是有點小激動,我再也不用擔心和后端同學加班聯調了,只要自己和自己聯通通過,保證前端這邊沒問題,剩下的交給后端同學慢慢調。
站住,別走!你這是在電腦上用瀏覽器訪問本地服務聯通自測通過,手機呢?公司局域網內手機能訪問電腦么?
手機直連電腦
先手機鏈接電腦試試行不行?先整簡單點的,我電腦和手機用的是家里的網絡,沒有網絡策略限制,看看能不能連上。
成功了,雖然情理之中,但是還是有點小開心。
多說一句,有的同學運行 ifconfig 命令找電腦 IP ,這樣有點費勁還傷眼睛,推薦個簡單優雅的。
接下來,連上公司 VPN 試試吧!
電腦連接公司 VPN 后,IP 地址不會變化,但是此時刷新手機網頁,毫無意外地訪問不了了。
既然走局域網不行,換個思路,直接斷開網絡,走 USB 直連呢?是時候讓 Android 調試橋上場了,電腦運行 adb reverse tcp:3000 tcp:3000 反向轉發 3000 端口請求,簡單說就是手機訪問 3000 端口會直接轉發給電腦 3000 端口代理,手機訪問看起來和電腦訪問一樣了。
讓我們拭目以待吧!
說實話,走到這,我的內心是崩潰的,咋還不行...手機訪問 http://192.168.101.17:3000/ 網絡不可用我能理解,畢竟網絡已經斷開,手機是沒法訪問電腦 IP 的。那么 http://localhost:3000 也不行,為什么啊?不是說 adb reverse 是端口反向轉發么,手機訪問 http://localhost:3000 等同于電腦訪問 http://localhost:3000 ,電腦訪問 http://localhost:3000 能正常打開頁面,為什么手機就不行了...掉坑里面去了,淡定!換成 http://127.0.0.1:3000 試試?快看,奇跡般地,手機竟然能訪問了,喜大普奔。
于是乎,網絡限制已被繞過,問題 ㈡ 被攻下。又可以開心地在公司手機訪問電腦服務了。
拼多多,似乎有著某種魔力吸引著大家。當別人在關心拼多多買東西有多便宜時,作為一個技術工,更吸引我的是為什么拼多多頁面這么快?
科學上網拼多多
瀏覽器直接打開拼多多首頁網址 http://pddwyb.com,不出意外地跳到了登錄頁,想讓我知難而退。
顯然,我還在繼續,就按他說的,手機號登錄試試。果然,已經防我這一手了,登錄后跳到首頁后又迅速跳回登錄頁。
有點意思,代碼都在我電腦上了,而且頁面還瞬間刷新了首頁,我又可以 Debug 頁面,這下還能難得倒我?畢竟大家學得都差不多,電腦在我手上,拿下只是時間問題!
如果我能在頁面跳回登錄頁前斷點暫停頁面,是不是就可以了?說干就干,看了一下 Chrome DevTools -> “源代碼” -> “事件監聽斷點” ,把幾個可能性比較大的打上對勾,刷新頁面,果然不出所料,斷住了。回過頭一看,只要把 “DOM 變更” -> “DOMContentLoaded” 勾上即可。
在跳轉到登錄頁前斷點停住了,這就是我要的效果。點擊瀏覽器導航欄 “文件” -> “頁面存儲為...”,這里注意格式要選擇“網頁,全部”,這樣相關的依賴文件也一塊存下來了。
直接打開存儲在本地的拼多多 Html 主文檔試試,第一眼首頁可以正常顯示,不錯。接著會看到控制臺一堆 CORS 跨域報錯和網絡失敗。
跨域問題很好解決,頁面路徑和依賴文件本來就是相同文件夾下,只不過直接通過文件的訪問方式會導致跨域問題。如果本地起一個 http-server 服務是不是就行了。Just do it!
運行 npm install http-server 安裝 http-server 依賴包,安裝成功后運行 ./node_modules/.bin/http-server . -p 8080 啟動本地 http-server 服務。
瀏覽器輸入 http://127.0.0.1:8080/pddwyb.com.html 看看吧。
接下來如果要解決跨域的話,可以像上面的 Express 搭的后端服務一樣,在網絡響應 header 里面加上 Access-Control-Allow-Origin:* 和 Access-Control-Allow-Headers:Content-Type 就可以,不過這么搞太麻煩。
通過拼多多首頁 Html 主文檔直接包括首屏靜態 DOM 信息可知,拼多多使用了服務端渲染(SSR)首屏優化技術,這就是我們要找的頁面打開為什么“快”的原因。
雖然 H5 代碼毫無秘密可言,但是畢竟經過混淆了,讀起來還是非常費勁的,一般不會直接改混淆后的代碼,而是采用追加執行代碼或者覆蓋代碼的方式。問題 ㈢ 搭建本地運行代碼也解決了。
是不是到這就可以了。答案是否定的!上面的手寫操作只是以最簡單的方式方便你理解原理,可以在特殊情況下多一些解題思路。真正的做法當然是站在巨人的肩膀上,借助強大的工具,Whistle(讀音[?w?s?l],拼音[wēisǒu]),剛好就是這樣的前端調試利器。
入深
Whistle 可以完全勝任前端抓包和 Mock 數據功能,最吸引我的地方是輕量和開源(免費),不過實測過程中還是遇到了一些缺乏說明或者缺乏詳細操作步驟等問題,導致始終不生效的情況,這也是我寫這篇文章的初衷,記錄下來給未來的自己以及屏幕前的你們。接下來我將 Whistle 可以用于提高我們工作中效率的功能點帶大家一步步走一遍,少些踩坑抓狂。
手機抓包
首頁必須是安裝 whistle ,考慮到國內安裝緩慢或失敗,運行 npm install whistle -g --registry=https://registry.npmmirror.com 指定鏡像安裝。安裝完成后,whistle、w2 和 wproxy 三個命令是等價的,都可以用于執行 whistle 命令。可以運行 w2 -V 看一下版本,如果能正常打印出來,說明安裝成功了。安裝完成后,運行 w2 start 啟動 whistle。
通過在瀏覽器打開 http://127.0.0.1:8899/#network 即可看到 whistle 網頁控制臺。
現在網絡請求基本都走 https ,要想抓包必須在電腦和手機安裝 https 證書。證書入口如上圖所示。證書下載后直接雙擊安裝,中間要求輸入密碼,然后如下圖將 whistle 證書選擇“始終信任”。
將電腦中下載好的 whistle 證書拷貝到手機,按下圖步驟安裝證書。
手機證書安裝成功后,將手機連接到電腦 whistle 代理服務,即手機網絡設置為手動代理到電腦IP地址(我電腦是 192.168.101.17 )和 3000 端口。注意,手機和電腦要連接同一個網絡。
手機連接電腦 whistle 代理服務后,你將會在電腦的 whistle 網頁控制臺抓住所有手機發送的網絡請求包,包含 HTTP、HTTPS、WS、WSS等。
在手機瀏覽器打開拼多多首頁 http://pddwyb.com/,抓包看看貨架瀑布流列表數據吧~
其實大部分開發是使用電腦瀏覽器,那邊電腦上啟動的本地服務能抓包 Mock 數據嗎?
模擬電腦本地服務假數據
雖然前端起的本地服務,可以在代碼里面寫假數據(簡稱 Mock 數據),但這樣畢竟對業務代碼有侵入性,如果刪除不干凈很可能帶到線上去了,通過前端代碼寫死假數據測試實屬無奈之舉。那么能不能在前端代碼不修改的情況下模擬假數據?答案必須能。先就著上面手機抓包拼多多數據,我們來 Mock 一下。通過抓包,也可以進一步佐證拼多多使用了 SSR 首屏渲染。
竟然首屏已經渲染好了,自然也就沒有 json 數據,所以只能 mock 貨架瀑布流第二頁數據。先給大家看看效果,再說怎么做的?
將拼多多首頁第二頁第一個標題“【超低價】2022板栗生栗子”改成“要求進步”,第二個標題“批發 白色 紅色 全新料無味”改成“不愧是你”。
做到上面 Mock 數據只需要簡單兩步。
Step 1:http://127.0.0.1:8899/#network?url=https://mobile.yangkeduo.com/proxy/api/api/jinbao/h5_weak_auth/goods/query_goods_list_by_opt_id_c_v2,點擊 Copy 按鈕復制貨架第二頁瀑布流數據。
點擊切換到 Values 頁,創建新文件 query_goods_list_by_opt_id_c_v2.json, 將復制的貨架瀑布流數據列表粘貼過來,修改第一個貨架 goodsName 值為“不愧是你”。注:修改完成后一定要保存文件,未保存時,文件名和 Values 均會飄紅點,這個務必注意一下,不保存將不生效。
Step 2:resBody://{query_goods_list_by_opt_id_c_v2.json} ,其中 resBody:// 表示替換返回數據,{xxx.json} 對應待 mock 數據。
配置好了再次刷新頁面,可以抓包看到 mock 修改后的數據已生效。這里要注意,修改內容后需要手動保存,注意 Values 和 Rules 左上角是否紅點,有則切換過去保存,不保存則對應修改的規則和數據不生效,對我來說是一次慘痛的抓狂教訓。
至此,我們完成了手機端數據 mock,電腦端 mock 也一樣。不過現在的問題是,如果斷開手機網絡,whistle 控制面板根本抓不到其他的網絡包。
如果要想抓包,必須請求走 whistle 的端口(默認 8899)代理,要想電腦瀏覽器可以被抓包,就需要設置瀏覽器端口(http 默認端口 80,https 默認端口 443)代理到 8899,有兩類方法可以做到。
方法一:w2 proxy on 打開代理, w2 proxy off 關閉代理。這一塊我也是被各種文檔坑得夠嗆。有的還打開“網絡偏好設置”->“高級”->“代理”->“網頁代理 HTTP”設置“127.0.0.1:8899”和“安全網頁代理 HTTP”設置“127.0.0.1:8899”。
其實, w2 proxy on 等價于在網絡面板高級里面設置 HTTP 和 HTTPS 代理為 127.0.0.1:8899, w2 proxy off 等價于取消設置。運行相關命令后可以在網絡面板高級選項中看看代理情況,兩種方式如出一轍。
方法二:
檢驗代理瀏覽器有沒有生效的最簡單方法就是看 http://local.whistlejs.com) 能否正常打開,能正常打開則表示設置瀏覽器代理生效。
當然了,代理生效也可以通過刷新頁面看是否有對應抓包信息來判斷。
整體來說,推薦的做法是安裝 SwitchyOmega 插件,這個插件還有其他高階功能待大家挖掘。這塊比較坑的是網上很多文檔都沒有講清楚這塊,其實是互斥關系,有的寫成了互補...,最坑爹的是有的插件建議下載壓縮文件安裝,安裝后不生效,導致我一直在互斥和互補中間很跳...,慘痛的教訓就是一定要去正規渠道 chrome 應用商店下載安裝,不行刪了再裝。
問題還沒完呢?雖然解決了電腦瀏覽器代理問題,但是本地起的服務,比方說上面搭的 express 3000 端口服務,訪問 url 為 http://127.0.0.1:3000,根本抓不著。其實本地開發前端代碼大都類似這種,如果不能抓包 Mock 數據,等于白忙活一場。
到這,粗暴地一頓瞎猜亂試肯定是行不通的,梳理一下計算機理論知識。這里涉及對 HTTP 請求和端口的理解。HTTP 默認端口號 80,正常情況下訪問 HTTP 請求不帶端口號,即默認 80 端口,也就是 http://www.baidu.com 等價于 http://www.baidu.com:80 。之所以 whistle 服務可以代理網絡請求,無一例外都將網絡端口指向了 8899,手機連接電腦對應網絡手動代理是 電腦IP:8899, 電腦瀏覽器對于服務代理是修改 HTTP 代理服務為 127.0.0.1:8899。也就是只有訪問 http://127.0.0.1:8899 才能被代理,http://127.0.0.1:3000 因為不經過 8899 端口,所以不會被代理,如果想被代理,唯一的方案是先訪問 http://127.0.0.1:8899,然后在 8899 端口轉發到 3000端口。
聽起來有點繞,直接上解決方案吧。
在 Rules 頁中新增轉換規則:^http://sheng.shuqiang.com$ http://127.0.0.1:3000。
直接通過 http://sheng.shuqiang.com 中轉訪問 http://127.0.0.1:3000 服務。
CROS 跨域問題
正如上面分析拼多多跨域問題的方案一樣,在網絡響應 header 里面加上 Access-Control-Allow-Origin:* 和 Access-Control-Allow-Headers:Content-Type 就可以。如果單獨起服務成本有點高,resHeaders://{corsheaders} Rules 可以完美解決了這個問題。
網頁追加腳本
上面科學上網拼多多也講過,直接看混淆后的代碼太費勁,常規操作是追加代碼操作 DOM 或者修正邏輯。恰恰 whistle 也具備這種功能。先看看點好玩的,一句追加代碼直接把“百度一下”改成“不愧是你”。
注入 vConsole 調試面板
運行 w2 i whistle.inspect 安裝 whistle.inspect 插件,規則中配置 http://sheng.shuqiang.com whistle.inspect://。
遠程 log
規則中配置 https://sheng.shuqiang.com log:// 即可在 Network 頁對應主文檔請求打印 console.log 日志。
看懂
寫到這,我簡單總結一下。
通過 Express 前端框架可以簡單搭建一下路由服務,用于代碼精細化控制返回內容。
通過 ADB 反向轉發接口,能做到斷網下通過 USB 線實現訪問網絡服務。
通過前端斷點、保存網絡文件內容、以及 http-server 可以獲取想怎么改就怎么改,有助于迭代更多的科學上網解題思路。
究極利器是屬于 whistle 的,強大的功能包含但不限于手機、電腦抓包或 Mock 數據、輕松解決 CROS 跨域問題、網頁追加腳本、注入 vConsole 調試面板和遠程 log,理論上通過轉發鏈接也能實現手機直連電腦服務。