Whistle 前端调试代理实战技巧
Whistle 是基于 Node.js 的跨平台抓包代理工具,支持 HTTP/HTTPS/WebSocket 拦截、请求转发、本地文件替换、接口 Mock,是前端日常调试利器。本文整理实战高频用法、踩坑难点、缓存问题终极方案。
官方文档:https://wproxy.org/
目录
- 快速安装与启动
- HTTPS抓包:证书正确安装(高频踩坑)
- 核心界面功能说明
- 常用基础规则大全
- 重点场景:本地静态文件替换(file://)
- [Values 面板深度使用](#Values 面板深度使用)
- [进阶:module:// 动态脚本处理请求](#进阶:module:// 动态脚本处理请求)
- 经典疑难问题汇总
- 最佳实践模板(直接复制使用)
1. 快速安装与启动
bash
# 安装
npm install -g whistle
# 启动代理(默认端口8899)
w2 start
# 停止
w2 stop
# 重启
w2 restart
访问管理面板:http://127.0.0.1:8899
浏览器/系统代理地址:127.0.0.1:8899
2. HTTPS抓包:证书正确安装(高频踩坑)
Windows 致命误区
❌ 不要双击证书直接安装!双击默认导入【当前用户】
certmgr.msc✅ Chromium(Chrome/Edge)新版策略:不信任当前用户导入的私有根证书
正确操作:
- 访问
http://127.0.0.1:8899/#cert下载根证书rootCA.cer - Win+R 输入 certlm.msc(管理员权限,本地计算机存储)
- 受信任的根证书颁发机构 → 导入证书
- 完全关闭所有浏览器窗口再重启
区分两个证书管理器:
certmgr.msc:当前用户(容易出现「证书安装成功依然不安全」)certlm.msc:本地计算机(全局生效,推荐)
Firefox 额外注意
Firefox 不读取系统证书库,需要在浏览器设置内单独导入根证书。
3. 核心界面功能说明
- Network:抓包列表,查看请求、响应、耗时、Headers
- Rules:规则配置面板,whistle核心,类似增强版hosts
- Values :内置资源仓库,存放JS/JSON/HTML,通过
{文件名}在规则引用 - Plugins:插件市场
Values 面板作用
Values 相当于 whistle 内置云文件仓库:
- 存放mock json、注入脚本、module脚本
- 规则中使用
{filename}引用,无需填写本地绝对路径 - 修改内容后必须点击 Save 生效
- 区别:
file:///xxx:读取电脑磁盘真实文件{demo.js}:读取Values内部文件
4. 常用基础规则大全
规则语法:
匹配url 操作://参数匹配顺序:从上至下依次执行;精确匹配 > 通配符匹配
4.1 请求转发(代理到本地后端)
# 将线上域名全部转发到本地 127.0.0.1:8888
test-api.example.com http://127.0.0.1:8888
# 路径匹配
test-api.example.com/admin-api/** http://127.0.0.1:8888/admin-api
4.2 修改请求头 / 删除请求头
# 新增/覆盖请求头
example.com/** reqHeader://Authorization=Bearer token123
# 删除指定请求头(重点!解决协商缓存304)
example.com/static/** reqHeaders://!If-None-Match
example.com/static/** reqHeaders://!If-Modified-Since
4.3 修改响应头
# 单数 resHeader:// 支持内置变量 ${randomUUID}
example.com resHeader://ETag="${randomUUID}"
# 复数 resHeaders:// JSON格式,【不支持变量插值】
example.com resHeaders://{"Cache-Control":"no-store"}
⚠️ 重要坑:
resHeaders://{}静态JSON模式不会解析${randomUUID},动态头必须使用多条resHeader://
4.4 Mock 接口响应
# 直接返回JSON字符串
example.com/api/user resBody://{"code":0,"data":{}}
# 读取Values内mock.json文件
example.com/api/user resBody://{mock.json}
# 模拟500报错
example.com/api/error statusCode://500
# 模拟网络延迟3秒
example.com/api resDelay://3000
4.5 页面注入JS脚本
# Values内存放inject.js
example.com js://{inject.js}
5. 重点场景:本地静态文件替换(file://)
开发最常用:线上JS/WASM/CSS映射本地文件
# Mac/Linux
example.com/static/** file:///User/xxx/statics/$1
# Windows
example.com/static/** file://D:/work/statics/$1
$1代表通配符捕获的路径,实现完整路径一一映射
重大已知缺陷(重点)
当规则同时使用 file:// 本地文件映射时,resHeader:// 内置变量 ${randomUUID} 不会被解析!
抓包可见响应头原样输出:ETag: "${randomUUID}",无法实现动态ETag。
解决方案两种:
- 首选方案:删除协商缓存请求头,治本
- 进阶方案:使用
module://{script.js}脚本手动构造响应头
6. Values 面板深度使用
6.1 基础引用
Values新建 mock.json
json
{
"code": 0,
"msg": "mock数据"
}
Rules:
example.com/api/list resBody://{mock.json}
6.2 module:// 脚本入口(高级能力)
Values创建 staticProxy.js,用于接管文件映射+动态修改响应头,解决file无法使用变量的问题。
javascript
const { v4: uuidv4 } = require('uuid');
module.exports = async function(ctx) {
// 读取本地文件
const filePath = `/User/xxx/statics/${ctx.params[0]}`;
await ctx.executeRule(`file://${filePath}`);
// 动态设置ETag
ctx.setResponseHeader('ETag', `"${uuidv4()}"`);
ctx.setResponseHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
}
Rules调用:
example.com/static/** module://{staticProxy.js}($1)
7. 进阶:HEAD请求引发缓存污染(真实业务痛点)
现象
浏览器先发 HEAD 请求校验资源,获取旧ETag;后续GET请求携带 If-None-Match,服务器返回304,whistle不会执行file本地文件替换,持续加载旧缓存。
根治完整规则模板
# 静态资源映射交给脚本处理
example.com/static/** module://{staticProxy.js}($1)
# HEAD请求同样走本地文件,禁止访问源站产生缓存
example.com/static/** method:HEAD module://{staticProxy.js}($1)
# 删除协商缓存请求头,杜绝304响应
example.com/static/** reqHeaders://!If-None-Match
example.com/static/** reqHeaders://!If-Modified-Since
8. 经典疑难问题汇总
问题1:规则配置了但是不生效
排查顺序:
- 确认代理已经正确指向whistle 127.0.0.1:8899
- Network面板确认请求被whistle捕获
- 检查规则匹配URL、通配符语法、顺序
- 清除浏览器缓存,关闭所有浏览器窗口重启
问题2:证书已安装,HTTPS网站提示不安全
- Windows:确认导入
certlm.msc(本地计算机),不要用certmgr.msc - 确认导入【根证书】,不是站点证书
- 关闭全部浏览器进程,不要只刷新标签页
问题3:file:// 本地文件替换,浏览器一直加载旧文件(缓存)
根因:协商缓存304,whistle不会下发本地文件。
不要只依赖修改ETag,必须删除 If-None-Match 请求头
问题4:resHeader://ETag="${randomUUID}" 原样输出不解析
原因:搭配 file:// 映射时内置变量解析失效;改用 module:// JS脚本动态设置响应头。
问题5:resHeaders://JSON 无法使用变量
官方机制:resHeaders://{...} 属于静态JSON,不支持模板变量;动态头使用多条 resHeader://key=value。
9. 最佳实践模板(直接复制使用)
模板1:线上静态资源代理本地文件(防缓存完整版)
# 静态资源代理脚本
www.example.com/static/** module://{staticProxy.js}($1)
www.example.com/static/** method:HEAD module://{staticProxy.js}($1)
# 移除协商缓存请求头,杜绝304
www.example.com/static/** reqHeaders://!If-None-Match
www.example.com/static/** reqHeaders://!If-Modified-Since
模板2:接口转发到本地服务
# 接口代理
test-api.example.com/admin-api/** http://127.0.0.1:8888/admin-api
# 跨域头
test-api.example.com/admin-api/** resCors://*
模板3:禁用缓存通用规则
# 全局禁用缓存
example.com/** resHeader://Cache-Control=no-cache, no-store, must-revalidate
example.com/** resHeader://Pragma=no-cache
example.com/** resHeader://Expires=0
如果你需要,我可以再补充:
- 配套的
staticProxy.js完整注释版本 - 一份可长期保存的通用Rules预设合集
- 移动端抓包(手机HTTPS)完整配置章节