前端应该知道的web调试工具——whistle
whistle 是什么
引用 官方的定义[1]
whistle
,拼音[wēisǒu])基于Node
实现的跨平台web
调试代理工具,类似的工具有Windows
平台上的Fiddler
,主要用于查看、修改HTTP
、HTTPS
、Websocket
的请求、响应,也可以作为HTTP
代理服务器使用,不同于Fiddler
通过断点修改请求响应的方式,whistle
采用的是类似配置系统hosts
的方式,一切操作都可以通过配置实现,支持域名、路径、正则表达式、通配符、通配路径等多种匹配方式,且可以通过Node
模块扩展功能
总的来说,whistle
有如下几个特性
- 基于
Node
实现,跨平台web
调试代理工具,window
,Linux
,Mac
都可以使用 - 用于查看、修改
HTTP
、HTTPS
、Websocket
的请求、响应,也可以作为HTTP
代理服务器使用 -
whistle
采用的是类似配置系统hosts
的方式,一切操作都可以通过配置实现 - 可以通过
Node
模块扩展功能
为什么选择 whistle
第一,whistle
是一个 web
调试代理工具,它的功能十分强大。作为一名前端,我们需要经常跟协议中的应用层打交道,Mock
数据、跨域问题、cookie
的修改、移动端调试等等,都是我们必备的技能,而 whistle
就能解决其中 90%
的问题
个人经常使用的一些场景如下:
- 绑定
Host
- 替换请求(
Mock
数据) - 使用
Weinre
或者vConsole
调试移动端页面 - 修改
cookie
- 往
HTML
中插入样式 - 往
HTML
中插入脚本 ...
以下为官方的一张图,大家可以感受一下
第二,除了功能十分强大,使用也十分便捷,只需要简单的命令就能打开网页进行抓包等操作
第三,不像 window
中的 Fidder
需要消耗大量 CPU
,也不像 Mac
中 Charles
不是免费的,它是免费的,开源的,而且一个跨平台 web
调试代理工具
第四,基于 Node
模块实现。可以通过 Node
模块进行扩展
以上,还没说服你的话,希望接下来的实战能够让你感受它的强大
安装
- 安装
Node
,推荐安装最新版的Node
,虽然whistle
支持v0.10.0
以上版本的Node
。这一个我相信大家作为一名前端都应该有的环境。这里多插一句,推荐使用n
管理node
版本 - 用以下命令安装
whistle
,如果很慢,请切换源进行安装。再插一句,推荐使用nrm
管理你的npm
源
npm install -g whistle
// Mac
sudo npm install -g whistle
- 启动
whistle
。通过命令w2 start
即可启动。启动之后,我们看到以下提示,就表示安装成功了
这里还需要留意其他几个经常使用的命令
w2 help // 查看帮助,里面很多常用的命令
w2 restart // 重启 whistle
w2 stop // 停止 whistle
w2 run // 调试模式启动whistle(主要用于查看whistle的异常及插件开发)
- 配置代理,分为全局代理、浏览器代理和移动端代理。这里主要谈谈
mac
端全局代理,chrome
浏览器代理以及IOS
侧的移动端代理。其他详情可以查看官方文档 安装启动[2]。需要注意的是,代理服务器:127.0.0.1
端口号:8899
。如果端口被占用,可以通过-p
来指定新的端口 1.全局代理(mac
):System Preferences
>Network
>Advanced
>Proxies
>HTTP or HTTPS
2.浏览器代理。首先先下载 Chrome
代理插件:推荐安装 SwitchyOmega[3] 。考虑到一些朋友无法很好的下载安装,可以去 这里[4] 下载。然后配置如下:
3.移动端代理。注意,要和当前电脑的 WIFI
是同一个 WIFI
。以 IOS
为例(安卓同理)
- 访问配置页面,一切顺利的话,访问 http://127.0.0.1:8899[5] 就可以看到相关的页面
- 还有一个很重要的步骤:安装根证书,假如不安装根证书的话,就不能抓
HTTPS
的包,详情请看 安装详情步骤[6]
以上就是我们的准备工作了,可能还是一些同学还是会遇到一些问题,可以去官方 issue[7] 看看有没有相关的解决方法,也可以留言评论,我们一起看看
界面讲解
对于新手来说,我们先熟悉下 whistle
的界面,有个大概的印象
以下是 whistle
的界面,常见的几个选项:
-
Network
——请求列表页面 -
Rules
——操作规则配置页面 -
Values
——存放KeyValue
的系统 -
Plugins
——插件列表页面
快速上手——基础使用【mock 数据以及解决跨域】
whistle
使用的是类似代理的方式,Rules
版面下默认有一个 default
的分组,我们可以创建、重命名、删除一个分组,可以根据以下示例快速建立一个分组,如动图所示:
接下来,我们就可以在右侧建立一些规则了。我们来拿掘金做个演示吧,掘金推荐首页获取列表数据的接口为 https://apinew.juejin.im/recommend_api/v1/article/recommend_all_feed
,以下是目前的页面,注意,该接口的响应头设置了 access-control-allow-origin: https://juejin.im
我们根据这个接口设置一条规则,以下规则表示完全匹配该接口,返回指定的 juejinList.json
数据,相当于 Mock 这个接口的返回
# 完全匹配,相当于 Mock 这个接口的返回
https://apinew.juejin.im/recommend_api/v1/article/recommend_all_feed file://{juejinList.json}
查看效果,报错了,看看报错,跨域问题,线上的之所以没有报错,原因在于,线上的接口的响应头设置了 access-control-allow-origin: https://juejin.im
,所以我们还应该 Access-Control-Allow-Origin
请求头
怎么办,就没有方法了么?当然不是,这个时候只需要多配置另外一条规则,总的规则如下:
https://apinew.juejin.im/recommend_api/v1/article/recommend_all_feed file://{juejinList.json}
https://apinew.juejin.im/recommend_api/v1/article/recommend_all_feed resCors://{cors.json}
其中 cors.json
内容为
origin: https://juejin.im
查看效果,可以看到访问掘金推荐首页,返回了我们代理的数据了
我们来看下 Network
版面,选中我们代理了的接口,可以看到已经走了我们所配置的规则了
上面我们是通过精确匹配匹配到了掘金的获取列表接口,写起来会很长,其实我们可以通过域名、路径、正则、精确匹配、通配符匹配等方式去匹配的,比如如下的规则也是可以的
/v1/article/recommend_all_feed/i file://{juejinList.json}
/v1/article/recommend_all_feed/i resCors://{cors.json}
基础的使用就是这么简单,这里我们就解决了 Mock
数据以及跨域的问题。当然,这只是 whistle
其中一个小功能,接下来才是重头戏
常用技能
解决跨域问题
可以通过 reqCors
修改请求的 CORS[8]。也可以通过 resCors
修改返回的 CORS[9] 。从而达到解决跨域的效果。上面的例子已经演示过,这里不再重复
Mock 数据
通过上面提到的 file://
协议,我们就可以 Mock
数据,当然你如果不想使用 Values
中的值,也可以使用本地的文件,类似如下的配置:
# 注意是绝对路径
/v1/article/recommend_all_feed/i file:///Users/gpingfeng/Documents/Personal/Test/juejinList.json
模拟 JSONP 返回
如果是 JSONP
,我们要怎么 Mock
呢?这里我们用到了 tpl
协议,tpl
协议基本功能跟 file
协议一样可以做本地替换,但 tpl
内置了一个简单的模板引擎,可以把文件内容里面 {name}
替换请求参数对应的字段(如果不存在对应的自动则不会进行替换),一般可用于 mock jsonp
的请求
这里我们拿京东首页的一个获取轮播图的接口作为演示。我们可以看到 URL
中指定的回调函数的 key
为 callback
,这个很重要,在配置 Values
的时候会用到
我们配置规则,修改返回为了路飞的图片
# 匹配到京东首页获取轮播图的接口,修改接口返回
/floor.jd.com/recommend-v20/focus_monetize/i tpl://{jsonp.json}
其中 jsonp.json
中的格式为
// callback 是根据上面 JSONP 请求中发送出去的回调函数决定的
{callback}({
// 这里是返回的 JSON,这里我就是替换了返回的图片而已
})
看结果,生效了
绑定 Host
一提到绑定 Host
,我们会想起使用 Switch Host
切换,但使用 whistle
可以更加方便和强大,不仅支持传统的 Host
配置,还支持子路径和端口的 Host
转发配置,我们可以将我们的环境放在不同的规则中,随时切换,而且无缓存,切换时候生效更快
本地代码,调试线上问题
有时候,我们遇到线上的问题,却因为数据问题,没有办法在本地复现。一般我们项目 api
的 url
都会设计带上后缀,利用这个,我们可以配置如下的规则,轻松调试线上的问题
# 接口走线上
^example.com/api/*** https://example.com/$1
# 访问走本地
^example.com/*** http://127.0.0.1:8120/$1
往 HTML 中插入 脚本 JS
jsAppend
协议往 content-type
为 html
或 js
的响应内容后面追加数据,如果是 html
,则会自动加上 script
标签在追加到响应内容,如果是 js
,则会自动追加到js文本后面
配置一个规则:
# 往掘金页面中注入脚本
/https://juejin.im/frontend/i jsAppend://{myJS}
查看效果:
查看源码,可以看到已经自动加上 script
标签在追加到响应内容
往 HTML 中插入 样式
cssAppend
往 content-type
为 html
或 css
的响应内容后面追加数据,如果是 html
,则会自动加上 style
标签在追加到响应内容,如果是css
,则会自动追加到文本后面
我们给掘金网页版加上暗黑模式吧,以下是 myCSS
html {
filter: invert(1) hue-rotate(180deg);
}
我们配置规则,插入到掘金中
# 往掘金中插入 CSS
/https://juejin.im/frontend/i cssAppend://{myCSS}
暗黑版掘金
查看网页源码,已经有了相关的 CSS
样式
修改 cookie
开发中,我们很多时候,需要设置请求头或者响应头的 cookie
,这个时候,我们就需要用到 reqCookies
和 resCookies
。它们的功能分别是修改请求头的 Cookie
和 修改响应头的 Set-Cookie
# 修改请求头的 `Cookie`
/apinew.juejin.im/interact_api/i reqCookies://{reqcookie}
# 修改响应头的 `Set-Cookie`
/apinew.juejin.im/interact_api/i resCookies://{resCookies.json}
reqcookie
内容如下:
name: 'Gopal'
like: 'FE'
效果如下:
resCookies.json
的内容如下
{
"name": "Feng",
"age": "26",
"happy": {
"value": "FE",
"maxAge": 60,
"httpOnly": true,
"path": "/",
"secure": true
}
}
效果如下:
真正的杀手锏——移动端调试
相比于在 PC
端,在移动端调试网页,主要会遇到以下两个问题:
- 没有
Console
,无法查看页面的js
错误及通过console.xxx
输出的调试日志 - 无法查看、修改页面的
DOM
结构及样式
虽然很多移动端页面,我们可以在 Chrome
的模拟器中进行调试,但不是所有的移动端页面都可以在 PC
端调试和复现问题。往往在 APP
中嵌入的页面,在不同的机器中会遇到兼容性问题,需要在真机中才能看到效果或者复现问题,这个时候就需要我们的 whistle
登场了
移动端捕获页面错误和 log
移动端,我们查看报错信息也是比较麻烦的,为此,whistle
提供了 log
功能如下:
https://juejin.im/frontend log://{test.js}
test.js
主要是模拟脚本报错,内容如下:
console.error({ error: true });
console.warn({ error: true, warn: { test: true } });
console.log(123456);
// 模拟抛出异常
console.notAFunction('test');
在 Network
—— Tools
下面就可以看到报错等日志了
具体的操作演示动画如下:
查看移动端页面的 DOM 样式
移动端的 DOM
样式查看和调试对于我们来讲也是一个比较头疼的事情。whistle
就能够做到轻松查看调试移动端的 DOM
样式,就跟调试桌面端的浏览器一样,这个是通过 whistle
内置的 weinre
去实现的
配置规则如下,其中 test
只是作为一个标识:
https://juejin.im/frontend weinre://test
演示动图以及效果如下:
使用插件——利用whistle注入vConsole
vConsole[10] 是微信团队开发的轻量、可拓展、针对手机网页的前端开发者调试面板,主要原理是通过在页面注入 js
实现模拟 PC
浏览器的 Console
功能
因为官方没有提供,所以我们这里选择使用插件的方法,顺便介绍下插件的用法(每个插件的用法不同,大家举一反三)
首先,安装插件
# 安装插件
npm i -g whistle.inspect
安装成功后,可以在 Plugins
页面中看到我们安装的插件:
安装插件后,只需配置简单的规则即可随意切换 vConsole
和 eruda
,这里我们只演示 vConsole
配置规则:
/juejin.im/i whistle.inspect://vConsole
演示动图如下:
插件开发
上面提到了插件的使用,为了满足一些特定业务场景的需要,whistle
也提供了插件扩展能力,通过插件可以新增 whistle
的协议实现更复杂的操作、也可以用来存储或监控指定请求、集成业务本地开发调试环境等等,基本上可以做任何你想做的事情,且开发、发布及安装 whistle
插件也都很简单。
whistle
的插件是一个独立运行的进程,这样是为了确保插件不会影响到 whistle
主进程的稳定性,并通过暴露一些 http server
的方式实现与 whistle
的交互,whistle
会在特定阶段请求特定的 server
,具体看下面的原理图:
从上面几个图可以知,whistle
插件会设计以下7种 server
,也就是有7种强大的功能
- statsServer:统计请求信息的服务
- resStatsServer:统计响应信息的服务
- rulesServer:设置请求规则的服务(支持
http/https/websocket
请求) - resRulesServer:设置响应规则的服务(支持
http/https/websocket
请求) - tunnelRulesServer:设置
tunnel
请求规则的服务 - server:
whistle
会把指定请求转发到该server
- uiServer:
whistle
插件的界面,可以通过特定的url
访问
结束语
whistle
作为一个强大的工具,我给大家介绍的只是其中一部分知识,但我坚信其中能够解决大家 80% 的问题了,希望能够对大家平时工作带来帮助。更多的使用技巧,大家可以查看 官方文档[11]
参考文章
- 官方文档[12]
- 利用whistle调试移动端页面[13]
- whistle--前端调试利器[14]
参考资料
[1]
官方的定义: https://wproxy.org/whistle/
[2]
安装启动: http://wproxy.org/whistle/install.html
[3]
SwitchyOmega: https://chrome.google.com/webstore/detail/padekgcemlokbadohgkifijomclgjgif
[4]
这里: https://github.com/FelisCatus/SwitchyOmega/releases
[5]
http://127.0.0.1:8899: http://127.0.0.1:8899/
[6]
安装详情步骤: http://wproxy.org/whistle/webui/https.html
[7]
issue: https://github.com/avwo/whistle/issues
[8]
CORS: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
[9]
CORS: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
[10]
vConsole: https://github.com/WechatFE/vConsole
[11]
官方文档: http://wproxy.org/whistle/
[12]
官方文档: http://wproxy.org/whistle/
[13]
利用whistle调试移动端页面: https://imweb.io/topic/5981a34bf8b6c96352a59401
[14]
whistle--前端调试利器: https://juejin.im/entry/6844903684736827400
- htcap:一款实用的递归型Web漏洞扫描工具
- 使用Go和Let's Encrypt证书部署HTTPS
- md5算法
- 《JavaScript高级程序设计》学习笔记(3)——变量、作用域和内存问题
- King Phisher:一款专业的钓鱼活动工具包
- 是不是Bash编程老司机,看完这10条细节就知道了
- 以针对Yahoo! 的安全测试为例讲解如何高效的进行子域名收集与筛选
- 线程池
- hbase 部署
- Hadoop源码系列(一)FairScheduler申请和分配container的过程
- MOTS攻击之TCP攻击
- iOS学习——获取当前最顶层的ViewController
- 中国深圳一家厂商的智能摄像头曝出漏洞:至少 17.5 万设备可被远程攻击
- iOS学习——Xcode9上传项目到GitHub
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Laravel监听数据库访问,打印SQL的例子
- PHP Swoole异步读取、写入文件操作示例
- PHP调用QQ互联接口实现QQ登录网站功能示例
- laravel解决迁移文件一次删除创建字段报错的问题
- laravel 错误处理,接口错误返回json代码
- Thinkphp 3.2框架使用Redis的方法详解
- Laravel validate error处理,ajax,json示例
- PHP 图片合成、仿微信群头像的方法示例
- python写文件时覆盖原来的实例方法
- Laravel 解决419错误 -ajax请求错误的问题(CSRF验证)
- PHP判断当前使用的是什么浏览器(推荐)
- PHP 计算两个时间段之间交集的天数示例
- laravel model 两表联查示例
- Laravel使用模型实现like模糊查询的例子
- Laravel 模型使用软删除-左连接查询-表起别名示例