深圳幻海软件技术有限公司 欢迎您!

从手写到 ADB 配合 Whistle 捣鼓前后端极度舒适的调试环境

2023-02-28

前因相信每一位前端程序员,在日常编写代码中,或多或少都会碰到前端三题:㈠有没有便捷的H5页面抓包和模拟假数据方法?㈡ 在公司网络限制下如何做到手机直连电脑服务,而不是通过费时费力的流水线打包访问测试服务器?㈢学习业界优秀的技术方案时,能不能直接“试”着“改”代码,所见即所得地剖(pōu)析

前因

相信每一位前端程序员,在日常编写代码中,或多或少都会碰到前端三题:

㈠ 有没有便捷的 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,理论上通过转发链接也能实现手机直连电脑服务。