使用 Whistle 拦截接口并模拟后端响应

前言

目标接口是 http://baidu.com/getWeather?date=2026-11-04&city=beijing,要的效果是请求打到 whistle 就停住,直接吐回北京 2026-11-04 的天气 JSON。

下面每条命令和每张截图都是在本机跑出来的。中途踩了几个坑,单独记在第 6 节。

0. 环境与基本命令

  • Windows
  • Node.js v22.22.2
  • whistle 2.10.13 不同版本的界面细节可能会有出入。

w2 的常用子命令:

命令 作用
w2 start 后台启动,关掉终端也还在跑
w2 run 前台启动,日志直接打到终端,Ctrl+C 结束
w2 stop 停掉后台进程
w2 restart 重启。改过配置或装过插件之后用
w2 status 看进程在不在、监听哪个端口
w2 proxy 把系统代理指到 whistle,w2 proxy 0 关掉
w2 ca 装根证书,需要解 HTTPS 时才用
w2 install <插件名> 装插件,uninstall 是卸

默认端口 8899,管理界面在 http://127.0.0.1:8899/。端口被占了就 w2 start -p 9000 换一个,之后 curl、浏览器代理、前端 proxy 配置里的端口都得跟着改。

启动时还有几个参数偶尔用得上:-S <目录> 换配置存储位置,-n 用户名 -w 密码 给管理界面加登录(默认没有密码,局域网里谁都能进)。

1. 安装并启动

Whistle 是个 Node.js 写的本地代理,装完就能用,不需要后端配合。

bash 复制代码
npm i -g whistle   # 约 10 秒
w2 --version       # 2.10.13
w2 start

启动成功后终端会打印可访问地址:

csharp 复制代码
[i] Whistle@2.10.13 started
[i] 1. Use your device to visit these URLs and note which one works:
       http://127.0.0.1:8899/
       ...
[i] 2. Set your device's HTTP PROXY to the working IP & PORT(8899)

浏览器打开 http://127.0.0.1:8899/,长这样就是起来了:

左边四个入口。Network 是抓包列表,走过代理的请求都落在这儿;Rules 是规则配置,这次要动的就是它;Values 存变量和常量;最后一个是插件管理。

2. 准备模拟数据

新建一个 JSON 文件,内容就是假后端要返回的东西。放在 mock/weather.json:

json 复制代码
{
  "code": 0,
  "message": "success",
  "data": {
    "city": "beijing",
    "cityName": "北京",
    "date": "2026-11-04",
    "week": "星期三",
    "weather": "晴",
    "weatherCode": "100",
    "temperature": {
      "current": 8,
      "high": 11,
      "low": -2,
      "unit": "℃"
    },
    "humidity": 34,
    "wind": { "direction": "西北风", "scale": 3, "speed": 12 },
    "aqi": { "value": 65, "level": "良", "pm25": 42 },
    "sunrise": "06:47",
    "sunset": "17:12",
    "tips": "昼夜温差较大,早晚注意保暖;空气质量良,适合户外活动。",
    "source": "whistle-mock",
    "mock": true
  }
}

存盘时注意编码选 UTF-8,否则中文会乱。后面规则里要用绝对路径引用它。

3. 配置拦截规则

3.1 打开 Rules 面板

点左侧 Rules。第一次进来顶部有一条黄色提示条,让你开启 HTTPS 抓包。这次全程走 HTTP,点 Got it 关掉就行。

面板分三块:左边是规则文件列表,自带一个 Default;右边是编辑区;顶部工具栏有 ON(全局开关)、Import、Export、Save、Create、Rename、Delete。

3.2 新建一个规则文件

点 Create,输入文件名 mock-weather,回车。左栏会多出这个文件,并且自动选中。

我没直接用 Default。实测它的启用状态不可靠,enabledCount 是 0,规则存进去也不生效。新建一个名字清楚的规则文件更稳,顺便也方便按项目区分。

3.3 写规则

在右边编辑区输入(一行一条):

bash 复制代码
baidu.com/getWeather file://E:/WorkBuddy/2026-11-04-09-57-42/whistle-mock-demo/mock/weather.json
weather.mock.test/getWeather file://E:/WorkBuddy/2026-11-04-09-57-42/whistle-mock-demo/mock/weather.json

第二行是留给浏览器验证的备用域名,原因见 6.4,不需要可以删。

语法就两段:

ruby 复制代码
<匹配模式>  <协议>://<参数>
部分 本例取值 说明
匹配模式 baidu.com/getWeather 域名加路径。不写协议头,也不写 query
协议 file:// 拿本地文件当响应体
参数 E:/.../weather.json 绝对路径,Windows 下用正斜杠

3.4 保存

点 Save。保存后左上角计数会变成 Enabled Rules (1)。

这步最容易漏。写完不点 Save,内容只留在浏览器内存里,代理那边一点反应都没有。

4. 验证

别急着看浏览器,先用 curl 强制走代理发一次,这样能排除掉浏览器自己的协议升级行为:

bash 复制代码
curl -x http://127.0.0.1:8899 -i "http://baidu.com/getWeather?date=2026-11-04&city=beijing"

本机实测输出:

css 复制代码
HTTP/1.1 200 OK
server: Whistle
content-type: application/json; charset=utf-8
content-length: 686
Connection: keep-alive

{
  "code": 0,
  "message": "success",
  "data": {
    "city": "beijing",
    "cityName": "北京",
    "date": "2026-11-04",
    "week": "星期三",
    "weather": "晴",
    ...
  }
}

这里有三个地方能说明请求根本没出去:状态码是 200(真实 baidu 的这个路径返回 404 或 301);响应头是 server: Whistle,不是 server: bfe/...;content-type 是 application/json,whistle 按 .json 后缀自己推断的,没手动设。

4.1 抓包列表

切到 Network,列表里会出现这条请求:

看 ServerIP 列,值是 127.0.0.1。真实请求这里会是远端服务器 IP。

4.2 看命中的规则

点中这一行,右侧 Overview 面板底部有 All Rules:

里面能看到 Status Code: 200、Server IP: 127.0.0.1、Response Body: 686(和文件字节数对得上),以及 rule: baidu.com/getWeather file://...,后面标着 From File: mock-weather。

规则没生效时这一栏是空的,所以它比看浏览器靠谱。

4.3 响应原文

切到 Inspectors,请求原文和响应原文都在,连响应头带完整 JSON:

4.4 浏览器

把浏览器代理指到 127.0.0.1:8899,直接访问接口地址,页面会把模拟的 JSON 渲染出来:

截图里访问的是 http://weather.mock.test/getWeather,不是 baidu.com。因为 baidu.com 在 Chrome 的 HSTS 预载列表里,浏览器会强行把它升级成 https,纯 HTTP 规则就命中不了。绕法见 6.4。

5. 让本地前端项目走 whistle

规则配好了,但前端 dev server 不走代理的话,请求还是能绕过去直达后端。两种接法。

方案 A:dev server 转发到 whistle

以 Vite 为例:

js 复制代码
// vite.config.ts
export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'http://127.0.0.1:8899',
        changeOrigin: false,   // 关键,别让 Host 被改写
      },
    },
  },
});

changeOrigin: false 这个别改。它保证 whistle 收到的 Host 还是 localhost:5173,你写的规则才能和浏览器地址栏里的 URL 对上。设成 true 之后 Host 变成 127.0.0.1:8899,规则全线失配。

方案 B:浏览器或系统代理

bash 复制代码
w2 proxy                    # 一键设置系统代理
w2 proxy "127.0.0.1:8899"    # 指定地址
w2 proxy 0                   # 关闭系统代理

可以再配个 SwitchyOmega 或 ZeroOmega,只代理目标域名。全局代理的话你所有流量都会灌进 whistle,抓包列表很快就没法看了。

6. 踩过的坑

# 现象 根因 解法
1 w2 start 显示 started,但 w2 status 说没实例,8899 也没监听 守护进程被回收了 改用 w2 run 前台跑,或者换普通终端执行 w2 start
2 curl http://127.0.0.1:8899 返回 502 upstream connect failed 系统里有 HTTP_PROXY 环境变量,请求被转给了别的代理 加 --noproxy '*',或 unset http_proxy https_proxy
3 规则写成 baidu.com/getWeather* 反而匹配不上 2.10.13 下路径尾部加 * 会让 query 部分匹配失败。不加通配符时,路径规则本来就会忽略 query 直接写 域名/路径,别加 *
4 curl 里生效,浏览器访问却是真实 404 baidu.com 被浏览器按 HSTS 升级成 https,whistle 只做隧道透传不解密,HTTP 规则命中不了 换非 HSTS 域名验证(weather.mock.test);或者开启 Enable HTTPS 并装 whistle 根证书
5 规则存了,init 接口也读到了,请求就是不生效 规则文件处于未启用状态,Enabled Rules (0) 新建自己的规则文件并 Save,确认左上角计数 ≥ 1
6 找不到规则存哪 2.10.x 把数据目录挪到了 .WhistleAppData C:\Users\<用户名>\.WhistleAppData\.whistle\rules\files\,文件形如 0.mock-weather
7 前端 fetch 报跨域 mock 响应默认不带 CORS 头 规则后面追加 resHeaders://{"access-control-allow-origin":"*"}

第 4 条还有个前因:whistle 自己也会把已知 HSTS 站点的 HTTP 请求 307 到 HTTPS。所以用 curl 验证永远最省事,它不会自作聪明改协议。

7. 切回真实后端

目的 操作
临时停用某条规则 行首加 # 注释掉,Save
全局停用 点 Rules 工具栏的 ON 切成 OFF
完全不走代理 w2 proxy 0,前端删掉 server.proxy
停掉 whistle w2 stop

8. 速查

bash 复制代码
# 安装与启动
npm i -g whistle
w2 start                                   # 或 w2 run 前台调试
w2 ca                                      # 要抓 HTTPS 时才装根证书
w2 proxy                                   # 设置系统代理
w2 proxy 0                                 # 关闭系统代理
w2 stop

# 验证,记得绕开系统代理变量
curl --noproxy '*' -x http://127.0.0.1:8899 "http://目标域名/接口路径?参数"

规则写法:

perl 复制代码
# 静态文件
域名/路径                file:///绝对路径/xxx.json

# 内联响应体 + 状态码 + 延迟
域名/路径                resBody://{变量名} statusCode://500 reqDelay://800
域名/路径                resType://json resBody://(直接写内容)

# 只改响应头,解决跨域
域名/路径                resHeaders://{"access-control-allow-origin":"*"}

规则到底有没有命中,看两处就够:curl 返回的 server: Whistle,以及 Overview 面板底部的 All Rules。

相关推荐
掘金者阿豪1 小时前
SQL Server数据迁移完成后,凌晨的数据库告警该怎么查?
前端·后端
JudithHuang1 小时前
React 嵌套路由与布局
前端·react.js·arcgis·react·react router
htzyl2061 小时前
前端阶梯——第四十三章、实战二:待办清单To-Do
前端·javascript·html
摹客2 小时前
【3D设计】界面设计中的3D元素:应用场景+5款工具横评(含Three.js)
前端
Hilaku2 小时前
CORS 到底在保护谁?90% 的前端理解错了跨域的本质
前端·javascript·程序员
wno7042 小时前
node.js中使用jquery
前端·node.js·jquery
阿琳a_2 小时前
b-map-viewer:面向 Vue 3 的地图可视化 SDK,从接入到展示再到交互分析
前端·javascript·vue.js·gis·数据可视化·地图
10年前端老司机2 小时前
Agent 商业化困局:热闹的发布会,冷清的付费客户
前端·后端·agent