工欲善其事,必先利其器。
工作以来主要从事移动端页面开发,移动端页面开发经常需要通过代理进行真机开发调试,期间使用过 Fiddler、SwitchHosts、Charles、Whistle 等代理工具,发现 whistle 使用起来效率最高;基于文本的配置方式比起 charles 基于 GUI 配置方式更为简单方便,而且基于 whistle 的插件扩展能力,可以实现更多定制功能,提升开发效率,改善开发体验,非常适合开发同学。
🏆 介绍
whistle 是基于 Node 实现的开源「跨平台 web 调试代理工具」,主要用于查看、修改 HTTP、HTTPS、Websocket 的请求、响应,也可以作为 HTTP 代理服务器使用;whistle 采用的是类似配置系统 hosts 的方式,一切操作都可以通过配置实现,支持域名、路径、正则表达式、通配符、通配路径等多种匹配方式,且可以通过Node模块扩展功能。
# Mac 查看系统 hosts 配置
$ sudo vi /etc/hosts
原理
whistle 会启动一个代理服务器,所有请求都先经过 whistle,然后再转发到真实服务器,所以可以在 whistle 拦截到请求的时候,对请求做很多定制化的操作,详细原理请查看 HTTP 代理原理及实现。
🚀 快速开始
安装
安装 whistle 前需要先安装 Node,为获取更好的性能,推荐安装最新版本的 Node。
# whistle 安装,Mac 或 Linux 的非 root 用户需要在命令行前面加 sudo
$ npm install -g whistle
最新版本的 whistle 支持三种等价的命令whistle、w2、wproxy ,本文使用 w2。
# 查看版本
$ w2 -V
# 查看帮助信息
$ w2 help
如果能正常输出 whistle 的版本信息,就表示安装成功了,后面可通过 help 命令查看帮助信息。
启动
whistle 常用命令如下,更多命令行参数请查看命令行参数。
# 启动
$ w2 start
# 重启
$ w2 restart
# 停止
$ w2 stop
whistle 启动后,可以通过 「whistle 控制台」 配置代理、抓包等,控制台功能介绍请查看界面列表。
配置代理
PC 代理配置
全局代理
全局代理是直接配置系统代理,配置后所有网络请求都会由 whistle 转发,使用模拟器开发调试时需要使用全局代理。
- Windows
- Mac:系统偏好设置 -> 网络 -> 高级 -> 代理 -> 网页代理(HTTP)&安全网页代理(HTTPS)
端口号默认为 8899,如果启动 whistle 时指定了端口号记得填入对应端口号。
浏览器代理
浏览器代理需要安装浏览器插件,浏览器配置代理后浏览器网络请求会进行代理,其他浏览器或者软件的网络不受影响。
- Chrome:安装 SwitchyOmega 插件。
移动端代理配置
移动端要配置代理的话,需要保证手机 WIFI 和 PC 是同一网络,下面以 iOS 为例,安卓类似。
服务器 IP 地址和端口可以在 whistle 控制台点击右上角 Online 查看。
安装证书
代理配置完成后可以到控制台抓包验证是否成功,这时你会发现只能抓取 HTTP 请求,如果需要抓取 HTTPS 请求,需要安装 whistle 证书,安装证书详细步骤请参考 whistle HTTPS。 证书安装完成后,还需要开启 HTTPS、Websocket 拦截功能。开启 HTTPS、Websocket 拦截和安装并信任证书,这两个条件缺一不可。 上述步骤缺一不可,都完成后就可以使用 whistle 进行代理开发调试了。
🛠️ 功能
whistle 提供基本上覆盖抓包调试工具可以做的所有功能,下图总结了 whistle 常用功能,完整功能请查看协议列表。
配置
whistle 的所有操作都可以通过如下配置实现,配置方式扩展于系统 hosts 配置方式(ip domain或组合方式ip domain1 domain2 domainN),具有更丰富的匹配模式及更灵活的配置方式。whistle 的匹配顺序是从左到右,这与传统 hosts 从右到左的配置方式不同,但为了兼容传统 hosts 配置方式,whistle 多数情况下位置可以调换,即:pattern operatorURI和operatorURI pattern等价。
为了阅读方便,建议配置从左到右书写,pattern operatorURI 不要随意调换位置。
pattern operatorURI
- pattern 为匹配请求 URL 的表达式,可以为域名、路径、正则以及通配符等多种匹配方式,具体内容请查看匹配模式。
# 域名匹配
www.example.com
# 路径匹配,支持带协议、端口
www.example.com/test
# 正则匹配
/^https?://www\.example\.com\/test/(.*)/ referer://http://www.test.com/$1
# 通配符匹配
^www.example.com/test/*** referer://http://www.test.com/$1
通配符: 域名、路径匹配不能满足一些复杂的情况,虽然正则匹配可以解决所有匹配问题,但门槛还是有点高,且涉及转义及设置匹配的起始位置等,对一些常用匹配 whistle 提供了一些更简单的配置方式,包含通配符匹配、通配域名匹配、通配路径匹配;通配符匹配模式必须以 ^ 开头(如果需要限制结束位置可以用 0...9 获取通配符匹配的字符串,其中 $0 表示整个请求 URL,更多用法请查看匹配模式 - 通配符匹配。
- operatorURI 为对应的操作,由操作协议 + 操作值组成。
operatorURI = operatorProtocol://operatorValue
- operatorProtocol(操作协议),对应某类操作,如:
# 本地替换,file 协议
pattern file://opValue
- operatorValue(操作值),对应具体操作的参数值,如:
# 本地替换,file 协议
pattern file:///User/test/dirOrFile # 或 pattern /User/test/dirOrFile
- pattern 和 operatorURI 支持组合模式,具体请查看配置方式。
# 传统组合方式
# 一个 pattern 对应多个操作
pattern operatorURI1 operatorURI2 operatorURIN
# 如果 pattern 部分为路径或域名,且 operator URI为域名或路径
# 这种情况下也支持一个操作对应多个 pattern
operatorURI pattern1 pattern2 patternN
常用功能
host 转发
本地开发时把请求转发到本地端口,可以用来去掉开发时 URL 中的端口号,转发后可以直接使用线上地址访问本地页面,能够解决本地开发时相对路径跳转以及接口跨域等问题,更多用法请查看 host 协议。
# 本地端口映射
# 线上地址:https://www.example.com/test
# 开发地址:https://localhost:4000/
www.example.com 127.0.0.1:4000
# 页面 a 会转发到页面 b
# 可用于调试内嵌 APP 页面,APP 内有一个入口链接 a,而调试的目标页面是 b
www.example.com/a.html www.example.com/b.html
修改请求头
修改请求头使用 reqHeaders 协议,可以用来配置后端接口泳道,大括号里面的值为操作值。
www.example.com/api/xxx reqHeaders://{key}
延迟响应
设置延迟响应时间(单位:毫秒)使用 resDelay 协议,可以用来模拟接口返回较慢。
# 模拟接口 5s 后返回
www.example.com/api/xxx resDelay://5000
修改响应状态码
修改响应状态码使用 statusCode 或者 replaceStatus 协议,可以用来模拟接口返回出错。 replaceStatus 是请求响应后再修改状态码,而 statusCode 请求不会发出去,设置完状态码直接返回。
# 模拟接口返回 500 错误
www.example.com/api/xxx statusCode://500
替换响应内容
把指定内容替换为响应内容( 304 等响应没有内容无法替换)使用 resBody 协议,可以用来 mock 数据。
# 指定内容替换为本地文件
www.example.com/xxx resBody://filepath
# 指定内容替换为 whistle 操作值
www.example.com/xxx resBody://{key}
追加响应内容
把指定内容追加到响应内容后面( 304 等响应没有内容无法追加)使用 resAppend 协议,追加到响应内容前面使用 resPrepend 协议,可以用来注入一些自定义脚本等,比如 vConsole 等。
# 指定内容追加到响应内容后面
www.example.com/xxx resAppend://{key}
# 指定内容追加到响应内容前面
www.example.com/xxx resPrepend://{key}
跨域
修改响应的 cors 使用 resCors 协议,可以用来解决跨域问题。
# `*` 表示设置 access-control-allow-origin: *
www.example.com resCors://*
# `enable` 表示设置 access-control-allow-origin: http://originHost
# 及 access-control-allow-credentials: true
www.example.com resCors://enable
移动端调试
移动端调试主要通过注入 vConsole、使用 weinre 远程查看、修改页面的 DOM 结构及样式,以及使用 log 打印日志 debug,具体用法请查看利用whistle调试移动端页面。
- 注入 vConsole
www.example.com jsAppend://{vConsole.js}
- weinre
# xxx 为对应的 weinre id,主要用于页面分类,默认为 anonymous
www.example.com weinre://xxx
- 打印日志
# xxx 为页面分类,为了方便同时调试不同的网页
www.example.com log://xxx
设置抓包样式
设置抓包列表行样式使用 style 协议,可以用来高亮指定请求,方便查看。
# color: 字体颜色,同 css color 属性,由于 `#` 为 whistle 注释符号,可以用 `@` 代替
# fontStyle: 字体样式,可以设置为 normal、italic、oblique 等
# bgColor: 对应列表行的背景颜色,具体设置同 color
www.example.com/api/xxx style://color=@fff&fontStyle=italic&bgColor=red
过滤配置
过滤配置使用 excludeFilter 和 includeFilter 协议,excludeFilter 表示排除匹配的请求,includeFilter 只保留匹配的请求。
# host 转发过滤后端接口请求
www.example.com 127.0.0.1:4000 excludeFilter://*/aweme/
清除缓存
Chrome 浏览器可以通过打开开发者工具,并勾选 Network 菜单里面的Disable cache实现禁用当前页面的缓存,移动端不支持这种方式,需要借助代理工具实现,用 whistle 清除页面静态资源缓存的方式主要为下面两种:
- 禁用页面 304 及缓存头:disable://cache
- 通过正则替换给页面里面长缓存静态资源链接添加随机参数:resReplace
# 禁用请求的缓存,只要经过代理且匹配到的请求都不会使用缓存,包括强缓存和协商缓存
www.example.com disable://cache
# 给页面中的 js、css 请求地址添加时间戳参数
# ``` assetsURL
# /\.(js|css)(['"])/g: .$1?time=${now}$2
# ```
www.example.com/index.html disable://cache resReplace://`{assetsURL}`
🔌 插件
为了满足一些特定业务场景的需要,whistle 提供了插件扩展能力,通过插件可以新增 whistle 的协议实现更复杂的操作、也可以用来存储或监控指定请求、集成业务本地开发调试环境等,基本上可以做任何你想做的事情。每个 whistle 插件就是一个普通的 npm 包,所以开发、发布及安装 whistle 插件都很简单;whistle的插件是一个独立运行的进程,插件运行不会影响到 whistle 主进程的稳定性。更多插件请查看 whistle-plugins。
常用插件
inspect
移动端页面开发时经常需要在页面上注入 vConsole 进行调试,一般做法是在 html 中引入 vConsole,开发环境打开,正式环境注释或者删除,容易不小心发布上线;还有个问题就是线上页面没法使用 vConsole 调试,使用 whistle.inspect 插件可以在不侵入页面代码的情况下注入 vConsole,线上页面也能注入。
# 安装 inspect 插件
$ w2 i whistle.inspect
在需要注入的页面配置:
www.example.com whistle.inspect://vConsole
🌰 项目实践
推荐使用全局代理,不会影响其他软件网络,全局代理方便使用「模拟器」进行移动端开发。
注意重启 Mac 后需要先启动 whistle 后才能访问网络。
- PC 端使用全局代理和浏览器代理都可以;
- 移动端推荐使用 whistle 全局代理 + 模拟器开发,效率非常高。
规则配置文件
初始化项目时在根目录下增加 .whistle.js 规则配置文件,其他同学在项目根目录下运行 w2 add 或者 w2 use 就可以添加这个配置;也可以通过类似 charles 导入、导出配置的功能。
// .whistle.js
const pkg = require('./package.json');
exports.name = `[${pkg.name}]本地环境配置`;
exports.rules = `www.example.com 127.0.0.1:3000`; // 多行规则用 \n 分隔
# 添加规则配置
$ w2 add