whistle 开发调试最佳实践

这是上周给学弟学妹们进行的一次线上分享,这里整理成了文章。

1. 什么是 whistle?

首先来看官网的定义是这样的:

whistle(读音[ˈwɪsəl],拼音[wēisǒu])基于Node实现的跨平台web调试代理工具,类似的工具有Windows平台上的Fiddler,主要用于查看、修改HTTP、HTTPS、Websocket的请求、响应,也可以作为HTTP代理服务器使用,不同于Fiddler通过断点修改请求响应的方式,whistle采用的是类似配置系统hosts的方式,一切操作都可以通过配置实现,支持域名、路径、正则表达式、通配符、通配路径等多种匹配方式,且可以通过Node模块扩展功能。

whistle 相当于一个连接客户端和远程服务器的“中转站”,当你向服务器发出请求后,代理服务器先获取用户的请求,再将服务请求转发至远程服务器,并将远程服务器反馈的结果再转交给客户端。

whistle 是一种正向代理,和 nginx 的反向代理刚好相反,那么两者有什么差异呢?可以看下面这两张图(图片来源于网络,侵删)。

正向代理:

反向代理:

用更通俗的话语来描述就是,假如我们去租房,这里我就是”客户端“,中介是”正向代理服务器“,房东是”互联网“,这里我为了找房子,就去某家找了中介,让他(代理服务器)帮我去寻找房源,这是一个主动的行为,是正向代理。

如果我们去租房,没有去找代理,我在某瓣租房小组找到了房源,现场去看房,结果发现这是个二房东,很生气。在这种场景下,”二房东“就是反向代理服务器,我们的目的是找房,但真正的房东(服务器)被中介(代理服务器)给屏蔽了,我甚至不知道房东(服务器)是谁。

通过 whistle 我们可以很方便的修改响应内容,比如 mock 各种状态码、错误信息,甚至是给网页插入一段脚本等。

2. 安装启动

安装 whistle:

npm install -g whistle

启动 whistle:

w2 start

打开 localhost:8899 就能看到界面了。更具体的代理配置步骤可以参考这个:

whistle 安装启动

切记下面这几个关键步骤:

  1. 勾选上 Enable HTTP/2
  2. 下载安装证书并信任
  3. 设置系统代理或者 switchyOmega 插件代理,如果用 Chrome 插件,记得点一下应用选项。

如果在 Network 可以抓到浏览器的请求,那就是配置成功了,不然就是证书或者代理没配置好。

3. 功能介绍

打开 whistle 的界面,主要是有这么几部分组成:

  1. 位于最顶部的工具栏,可以设置清空列表、录制、筛选、重放等功能
  2. 位于中间的内容区,在 Network 下展示的是抓到的网络请求,在 Rules 下是设置的代理规则,在 Values 下是设置的变量,在 Plugins 下是安装的插件。
  3. 最右边的请求详情信息,主要展示选中请求的具体信息。

3.1 Network

Network 主要是展示抓到的请求列表,通过上方的 Clear 可以清除列表,通过 Settings 里面的 filter 可以筛选某些部分请求。

右键选中某条请求,还可以将其生成一个二维码,直接扫码就能发送对应的请求。还可以看到右边的请求详情信息。主要有请求头、请求参数、响应头、响应数据、cookie、log 等等信息。

3.2 Rules

Rules 是设置代理规则的地方,可以通过 create 来创建不同的规则分类,方便将同一个项目的代理规则放到一起。

还可以通过 enable/disable 来切换代理规则是否生效,是一个比较常用的功能。

4. 设置 hosts

如果你有搜索过【如何访问谷歌】这类问题,应该会看到有些教程会告诉你修改电脑的 hosts 文件,将 www.google.com 设置到他们给的一个地址,这样就实现了通过代理服务器来访问谷歌,这就是前面说过的正向代理。

通过 whistle 我们可以不修改系统的 hosts 文件就做到这样的事情。

在 whistle 的 rules 里面创建一个分类,比如叫 test,在 test 里面增加下面这条规则:

https://www.baidu.com/ localhost:3000

我在本地使用 Vite 启动了一个项目,监听 3000 端口,可以看到下面的效果。虽然打开的是百度,但实际上展示的是 localhost:3000。

打开 Network 看 www.baidu.com 这条请求的详细信息,可以看到实际上生效的 Url 是 localhost:3000。

因此,在开发中我们经常使用这种方式,将测试环境的域名代理到本地的 localhost,这样就能够在本地请求到测试环境的接口,不需要​单独在项目里配置请求的 apiproxy,非常灵活方便。​

4.1. 代理到本地

4.1.1 代理 html 文件

除了代理到另一个域名,还可以将线上代理到本地的文件。随便找一个目录,里面创建一个 index.html 文件,在文件里面写上 hello, 我是百度。

接着来设置一下新的代理规则,将代理地址设置为这个 index.html 的绝对路径。

https://www.baidu.com/ file://${projectPath}/test/index.html

上面使用到了 projectPath 这个变量,在 whistle 里面支持我们定义变量,方便之后复用。如果我们的工作目录是固定的,那就可以将其设置为变量,避免重复写路径前缀。以 Mac 为例:

    ``` projectPath
    # 上面访问的就是 /Users/你的用户名/Desktop/project/test/index.html
    /Users/你的用户名/Desktop/project
    ```

除了这种方式,还可以将变量定义在 Values 目录下,在 Values 下创建一个叫 projectPath 的 key,将上面的路径写进去。

那么我们打开百度看看效果吧。

4.1.2 代理静态资源

除了代理 html 文件,我们还可以代理静态资源到本地,如果你想修改线上的 JS 资源,这是一个很好的办法。

打开百度,可以看到他的静态资源都在 https://dss0.bdstatic.com 这个域名下,那么可以对这些资源进行代理。

# https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman file://${projectPath}/test

Disable Cache 后刷新页面再来看一下,发现请求的资源都返回了 404,这是因为我本地的 test 目录里面没有这些资源,也说明已经成功代理过去了。

4.2 代理响应内容

whistle 还支持我们修改响应内容,方便对接口进行一系列的开发调试。我在这里将请求百度的响应代理到 test.json,在 Values 里面创建一个叫 test.json 的 key,里面写上一串 json 数据,这样返回的就是一个 json 数据。

https://www.baidu.com/ resBody://{test.json}

最终的效果是将这个 json 的内容输出到页面上了,这是因为 Content-Type: text/html 这句告诉浏览器当前响应的是个文档。

如果对响应 json 的接口进行代理,那么就能 mock 各种返回的数据和异常场景了。

4.3. 解决跨域

跨域是 Web 开发中经常遇到的问题,常见解决方式是 CORS,通过设置 Access-Control-Allow-Origin 响应头来允许指定的域名跨域访问。

通过 whistle 我们可以增加 Access-Control-Allow-Origin 响应头,这样就能实现跨域。

www.baidu.com resCors://*

在 Network 里面可以看到,www.baidu.com 的响应头里面已经增加了 access-control-allow-origin: * 这一项。

4.4. 修改 ua

whistle 提供了语法来支持修改请求的 userAgent,但这个只对请求生效,不会对本地的 userAgent 生效。因为它本质上还是修改了请求头里面的 userAgent。

https://www.baidu.com/ ua://{ua}

那么我们将请求百度的 ua 设置为 windows phone 来看一下效果。

Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; RM-1113) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586

再次打开百度,发现页面已经变成了 H5 模式,虽然我们是用 PC 打开的。

来看一下请求的详情,发现请求头里面的 userAgent 已经被我们修改了,但本地 navigator.userAgent 的并不会被修改,因为 whistle 只会修改请求。

4.5. 自定义样式

除了修改请求的信息,whistle 还支持自定义某个域名下的请求展示样式。试试下面这串代码:

www.baidu.com style://color=@fff&fontStyle=italic&bgColor=red

5. 实战 —— 绕过网站付费

前面讲了这么多年规则用法,那么这里来带大家进行一次实战。通过 whistle 来绕过某付费网站。

成人依恋类型量表 是一个在线测评网站,但它是付费的,当我们点击开始测试,就会弹出这个付费的弹窗。那么有没有办法绕过这个付费呢?

那么我们先来看一下点击开始测试的时候它做了什么事情吧,我们盲猜会去向后台发送接口,获取用户的 vip 信息,然后判断是否弹窗。那么打开开发者工具来看一下吧。

很显然,这里调用了 toolcheck 接口来获取是否 vip,那么我们是否可以通过修改接口返回的数据来绕过 vip check 呢?答案是可以的。

我们先来看一下这个请求的调用栈,很容易发现是在 tool.js 的 loadtoolcheck 里面调用的。

这个函数明显是发送了一个 ajax 请求,数据返回后就会调用 success 方法,那么在 success 的判断条件里面都打上断点,重新点击开始测试看一下效果。

可以看到,这里有进行了一次判断。如果接口响应结果是 ok 的话,那就将某个变量设置为 true,并且隐藏加载弹窗。这里不得不吐槽一下这个变量的拼音命名了,hideLoading 写成了 hidejiazai。

所以在这里,我们只需要将这个接口的返回结果通过 resBody 修改成 ok,那么就绕过了这个网站的 check vip 逻辑。再次打开发现已经不会弹窗了,可以直接进入了答题测试页面,很完美。

    ```vip
    ok
    ```
    https://www.zxgj.cn/gongju/toolcheck resBody://{vip}

除了修改接口响应,这里还有另外一种办法,那就是把这个 js 文件复制一份到本地,并且将这些 if else 的判断逻辑删掉,只保留 if 里面的内容。

然后我们将这个 JS 文件代理到我们本地修改后的 JS 资源里面,这样也完美绕过了 check 逻辑。刷新页面后再次打开,发现 JS 文件的内容已经变成了我们本地的。

6. 移动端调试

whistle 很常用的一个功能就是移动端调试。虽然在移动端测试环境可以通过 chrome://inspect 的形式来调试 webview,但对于线上的一些应用来说,经常会屏蔽掉,导致我们调试也没那么容易。

想象一下,线上的 H5 页面出了 bug,但你又不知道到底是哪里有问题呢?是接口返回的不对?是 localStorage 不对?是某个样式没生效?还是...?

完全靠盲猜来定位 bug 是非常痛苦的。最恐怖的方式是通过临时增加日志,然后发版的形式来定位 bug。

6.1 安装

我们在移动端依然需要进行 whistle 的配置,首先要保证手机和电脑连接的是同一个 wifi 网络,然后打开 wifi 详细配置,将代理设置为手动,服务器是你自己电脑的 ip 地址,端口号是 8899,然后需要在手机上去下载 whistle 的证书,安装后对其信任。

当我们在 Network 里面可以看到手机上的请求时,说明代理已经配置生效了,这个时候你在电脑上的代理规则,对手机也一样起效。

6.2 注入 vConsole

vConsole 是一个非常好用的移动端调试小工具,它的界面类似 Chrome 开发者工具,有 Console、Element、Network、Storage 等几个功能,可以帮助我们快速获取页面的一些基本信息。

但是 vConsole 只适合在测试环境使用,或者在生产环境通过某种特别的手段调出来(比如1s内连续点击10次某个按钮),它不应该展示给用户,这样就容易暴露一些信息。

所幸的是,whistle 提供了 jsPrepend 这个语法允许我们对某个页面注入 JS 脚本。这样我们打开页面的时候,vConsole 就已经注入了,只对我们连接了代理的手机才会生效。

https://www.baidu.com/ jsPrepend://{vConsole.js}

我们可以从网上把 vConsole 的源码下载下来,在 Values 里面创建一个叫 vConsole.js 的 key,将源码复制进行,并且将 vConsole 这个类进行实例化。

再次打开百度,发现右下角已经出现了 vConsole 的小按钮,接下来我们就可以愉快的进行各种调试了。

6.3 打印日志

除了注入 vConsole 这种方法,还可以开启日志打印,只需要设置下面这一条规则:

https://www.baidu.com/  log://

再次打开百度,就能够在 Network 的 Tools 下面的 Console 选项下面看到控制台打印的所有 log 信息了。这种方式也比较适合在移动端进行一些调试。

7. mock 接口返回

最后这部分是用于进行接口的一些调试,方便测试开发对后端的接口提前进行测试,也方便前端开发来模拟各种接口的异常场景。

7.1 修改接口返回状态码

whistle 支持我们修改接口返回的状态码,如果你想测试接口返回异常状态码(403、404、500、503等等)的情况,此时你的异常处理逻辑是否生效,但后端不愿意配合你把接口改成500,那么你就可以自己用 whistle 来模拟。

比如我们将 www.baidu.com 的返回设置为 404,可以看到下面这个找不到网页的报错。

https://www.baidu.com/ statusCode://404

7.2 修改接口返回数据

我们可以对接口返回的数据进行一些修改,这样可以模拟各种场景。假如我们有一个列表页,我想测试没有数据、100条数据、1000条数据、10000条数据的情况。

参考网易云音乐的搜索页面,我们搜索【周杰伦】出现了很多搜索结果,假如我们想测试没有搜索结果的情况呢?

可以拦截列表的请求接口,将接口里面返回的数据设置为空数组。再次搜索周杰伦,神奇的发现居然搜不到相关的结果了!

https://music.163.com/weapi/cloudsearch/get/web resBody://{netease.json}

7.3 模拟超时

whistle 还可以模拟超时,对于前端开发比较有帮助。一个是我们需要测试超时的异常处理逻辑是否正确,另一个是我们可能需要验证超时重试机制是否生效,这个完全依赖于后端来配合效率会比较低。

www.baidu.com reqDelay://5000 enable://abort

7.4 模拟弱网

whistle 除了可以模拟超时,还可以模拟弱网。虽然 Chrome 本身也可以模拟 2G、3G、4G 等网络环境,但 whistle 可以精确到具体的网络传输速度。

比如我们设置请求 www.baidu.com 的网速是 10kb/s,会发现网页打开速度非常慢,加载耗时达到了 14s 之久。

8. nohost

nohost 是腾讯开源的一个基于 Whistle 实现的多用户多环境配置及抓包调试系统,个人觉得是 whistle 生态的一个大杀器。借用 Github 的介绍就是:

  1. 环境共享:前端无需配后台环境,后台无需配前端环境,其他人无需配任何环境
  2. 抓包调试:远程实时抓包调试,支持各种 Whistle 规则,以及通过链接分享抓包数据
  3. 历史记录:可以把环境配置及抓包数据沉淀下来,供后续随时切换查看
  4. 插件扩展:可以通过插件扩展实现诸如 inspect,vase,autosave 等功能
  5. 对外接口:提供对外接口,可供发布系统、CI等工具操作,实现自动化增删查改环境配置

目前 nohost 在腾讯这边广泛使用,我们这边也是通过 nohost 来进行的多环境配置和调试。它的好处在于,假设你在自己分支实现了一个功能,想给产品看一下,那么就可以通过 nohost 来部署一套自己的环境,产品只需要在界面上一键切换到你的环境,那么就能够看到你分支上的代码了。

通过界面来一键切换环境:

在开发环境中:

一般来说,nohost 需要配合 CI 来使用。比如我们分支的代码推送后,触发了 CI 构建,它会将构建结果放到以你的特性分支为目录名的文件夹里面。

在界面切换环境的时候,就会根据选中的环境从对应的文件夹里面读取我们的静态资源,这样就实现了多套环境切换,非常方便。

9. 最后

whistle 是一个非常方便开发调试的工具,利用好 whistle 可以发挥你想象不到的作用。更多的 api 也可以参考 whistle 的官方文档:whistle

最后,本文的所有代理配置如下:

    # 这里的 ``` 语法和 md 的代码块冲突了,所以缩进了一个 tab,看起来怪怪的。
    ``` projectPath
    /Users/gloryyin/Desktop/project
    ```

    ```ua
    Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; RM-1113) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586
    ```

    ```vip
    ok
    ```
# 设置 hosts

# 代理到本地 localhost
https://www.baidu.com/ localhost:3000
# 代理到本地 html
https://www.baidu.com/ file://${projectPath}/test/index.html
# 代理响应内容
https://www.baidu.com/ resBody://{test.json}
# 代理
https://www.baidu.com/ https://www.google.com.hk/
# 修改ua
https://www.baidu.com/ ua://{ua}
# 自定义样式
www.baidu.com style://color=@fff&fontStyle=italic&bgColor=red
# 代理资源
https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman file://${projectPath}/test
# 跨域
www.baidu.com resCors://*

# 例子 https://www.zxgj.cn/g/ecr?key=0cTtkPxO
https://www.zxgj.cn/gongju/toolcheck resBody://{vip}
https://www.zxgj.cn/resource/js/tool.js file://${projectPath}/test/tool.js


# 移动端调试
# 注入 vConsole
https://www.baidu.com/ jsPrepend://{vConsole.js}
# 打印日志
https://www.baidu.com/  log://

# mock 接口返回

# 修改接口返回状态
https://www.baidu.com/ statusCode://404
# 修改接口返回数据
https://music.163.com/weapi/cloudsearch/get/web resBody://{netease.json}
# 模拟 5 秒超时
www.baidu.com reqDelay://5000 enable://abort
# 模拟弱网
www.baidu.com resSpeed://50
本站文章资源均来源自网络,除非特别声明,否则均不代表站方观点,并仅供查阅,不作为任何参考依据!
如有侵权请及时跟我们联系,本站将及时删除!
如遇版权问题,请查看 本站版权声明
THE END
分享
二维码
海报
whistle 开发调试最佳实践
whistle 相当于一个连接客户端和远程服务器的“中转站”,当你向服务器发出请求后,代理服务器先获取用户的请求,再将服务请求转发至远程服务器,并将远程服务器反...
<<上一篇
下一篇>>