1. 这不是“造数据”,而是前端联调的呼吸节奏控制术
Mock 接口数据实操,规则改写和断点拦截的联调——这标题里藏着三个被日常开发严重低估的关键动作:数据可控性、请求可塑性、交互可暂停性。它不是教你怎么用一个工具生成假JSON,而是解决一个真实到让人皱眉的现场问题:后端接口还没上线,UI已交付,测试用例要跑通,产品经理在群里@你问“页面空白是不是你代码没写好”,而你心里清楚,是那个叫/api/v2/user/portfolio/summary的接口还在联调环境里打盹。这时候,Mock 不是备胎,是主驾;规则改写不是配置项,是翻译器;断点拦截不是调试开关,是时间暂停键。我带过六支前端团队,90% 的联调阻塞不是出在代码逻辑,而是卡在“等接口”这个单点上。真正高效的 Mock 实践,必须同时满足三个硬指标:第一,前端能独立构造任意结构、任意状态码、任意延迟的响应(比如模拟网络超时返回504,或模拟登录态失效返回401);第二,能对真实发出的请求做动态重写——把/dev-api/user临时映射成/mock/user,甚至把请求体里的userId=123替换成userId=999用于边界测试;第三,能在请求发出前、响应返回后、甚至响应流中间任意位置插入断点,像外科医生一样精准切开HTTP生命周期,查看原始请求头、修改响应体字段、注入错误信息再放行。这三个能力叠加,才构成完整的“联调呼吸控制”。它不依赖后端进度,不污染生产环境,更不靠“我本地能跑”这种模糊承诺。尤其在金融、电商这类强状态、多分支场景下,mock 数据必须能表达“持仓为0但有挂单”、“订单已支付但风控未通过”、“行情推送中断后重连成功”等复合状态——这些根本不是随机生成的JSON能覆盖的。所以别再搜“charles mock数据教程”只学怎么配host了,今天这篇,我们从真实项目日志出发,拆解一套可落地、可审计、可交接的 Mock 联调工作流。
2. 整体设计思路:为什么必须三线并行,而不是单点突破
2.1 单一Mock工具的致命盲区:它只管“输出”,不管“输入”和“过程”
很多团队起步就选 Mock Server 类工具(如 Mockoon、WireMock),理由很实在:界面友好、启动快、JSON写得顺。但三个月后必然遇到三类典型卡点:第一,前端发的是https://prod-api.example.com/user/profile,Mock Server监听的是http://localhost:3000/mock/user/profile,你得全局替换所有fetch调用里的URL,或者让Webpack DevServer做代理重写——一旦代理规则写错,整个页面白屏,排查成本远高于写Mock本身;第二,想测试“用户余额不足时提交订单失败”的场景,需要后端返回特定错误码+错误文案,但Mock Server只能静态返回预设JSON,无法根据请求体里的amount=99999动态判断是否触发余额校验逻辑;第三,最要命的是,当发现某个接口返回的数据格式和文档不符时,你根本看不到原始请求到底发了什么——Header里少传了X-Auth-Token?Query参数拼错了?Body里日期格式是2024-01-01还是2024/01/01?Mock Server作为服务端,天然收不到请求发起前的状态。这就导致一个问题:Mock解决了“有没有数据”,却放大了“数据对不对”的不确定性。我去年接手一个股票行情项目,前端反复报“K线图不渲染”,查了两天才发现是WebSocket连接时,前端漏传了market=SH这个Query参数,而Mock Server压根不记录请求元信息,所有排查都靠猜。
2.2 三线并行架构:让Mock成为可观察、可干预、可验证的透明管道
我们最终落地的方案,是把Mock能力拆解为三个协同层,每层解决一类问题,且全部运行在开发者本地:
第一层:请求拦截与重写层(Charles/Fiddler/浏览器DevTools Network面板)
它位于浏览器和真实服务器之间,像交通指挥中心,能看见每一辆“请求车”的车牌(URL)、载货清单(Headers/Body)、目的地(Host)。核心价值是零代码侵入式重定向:不用改一行业务代码,就能把所有/api/开头的请求,实时重写为/mock/路径;还能动态修改请求参数,比如把?page=1&size=10改成?page=1&size=1强制触发分页异常;甚至能注入自定义Header,模拟不同登录态。这一层解决的是“请求能不能被正确捕获和改造”。第二层:规则驱动Mock层(基于MSW或自研轻量Mock引擎)
它不直接监听端口,而是作为前端代码的一部分,在浏览器内存中运行。通过声明式规则(如rest.get('/api/user/:id', (req, res, ctx) => {...}))匹配请求,并返回动态响应。关键优势在于上下文感知:能读取req.url.searchParams.get('id'),能解析req.body,能根据当前时间计算Date.now() > deadline返回不同状态。我们曾用它模拟“交易时段内允许下单,非交易时段返回维护中”的逻辑,纯靠JSON配置根本做不到。这一层解决的是“响应能不能按需生成”。第三层:断点调试层(浏览器DevTools的XHR Breakpoints + 自定义拦截钩子)
它不是附加功能,而是贯穿前两层的“手术刀”。在Chrome DevTools里设置XHR/fetch断点,请求发出瞬间自动暂停,你能看到完整的Request Headers、Payload、Response Headers,甚至能手动编辑响应体再继续执行。更进一步,我们在MSW规则里嵌入debugger语句,或在Charles里配置“Break on Response”,实现毫秒级介入。这一层解决的是“整个链路能不能被完整观测和干预”。
这三层不是替代关系,而是流水线:请求先被拦截层捕获并重写 → 重写后的请求进入规则层匹配并生成响应 → 响应返回前由断点层捕获供人工检查。三者缺一不可。比如测试“弱网环境下订单提交超时”,你需要:拦截层将/api/order/submit重写为本地Mock地址;规则层设置ctx.delay(8000)模拟8秒延迟;断点层在响应返回前暂停,手动修改状态码为0(模拟网络中断)。单点工具永远无法覆盖这种组合场景。
2.3 为什么放弃“一站式”方案?安全、可控、可审计是底线
市面上确实有“All-in-One”工具,比如Postman Mock Server配合Proxy,或某些IDE插件。但我们明确拒绝,原因有三:
第一,安全边界模糊。这类工具常要求你配置“信任所有HTTPS证书”或“允许本地代理”,一旦配置失误,真实生产请求可能被劫持。我们曾发现某团队用某款国产Mock工具,因SSL配置错误,导致测试环境的/api/login请求被重定向到本地,用户密码明文暴露在控制台日志里。
第二,行为不可审计。当出现“Mock数据突然不生效”时,你无法快速定位是规则没匹配、拦截没生效,还是断点被误关。而分层架构下,每层都有独立日志:Charles显示“Request intercepted for /api/user”,MSW控制台打印“[MSW] GET /mock/user matched”,DevTools Network面板标记“Paused on fetch”。三份日志交叉验证,5分钟内必定位。
第三,技术栈绑定风险。所谓“Vue3 TS的mock使用教程”,本质是教你怎么在Vite配置里加server.proxy。但当项目后期接入微前端,主应用用React、子应用用Vue,代理规则会变成维护噩梦。而我们的分层方案,拦截层在浏览器端,规则层在各子应用独立配置,完全解耦。
所以,这不是炫技,而是用稍高的初期学习成本,换取后期90%的联调时间节省。当你能对着产品经理说“这个需求我明天就能给你可交互Demo,不需要等后端”,你就掌握了前端真正的主动权。
3. 核心细节解析:规则改写与断点拦截的实操铁律
3.1 规则改写的三大禁区:URL重写、Header篡改、Body注入的生死线
规则改写不是简单的字符串替换,而是HTTP协议层面的精密手术。我见过太多人栽在看似微小的细节上,导致Mock环境和真实环境行为不一致,最终上线翻车。
第一禁区:URL重写必须保留原始协议与Host头
常见错误操作:在Charles里把https://prod-api.example.com/api/user重写为http://localhost:3000/mock/user。表面看能拿到数据,但埋下两个雷:
- 雷一:前端代码里如果有
window.location.origin拼接API地址的逻辑(比如上传文件时用origin + '/upload'),重写后origin仍是https://prod-api.example.com,但请求发到了http://localhost,跨域报错; - 雷二:某些金融接口强制校验
Referer或OriginHeader,重写URL后这些Header没变,但服务端一看“你从生产域名来却访问本地Mock”,直接拒绝。
正确做法:使用Charles的“Map Remote”功能,将prod-api.example.com这个Host映射到localhost:3000,同时保持URL路径和协议不变。这样浏览器发出的仍是https://prod-api.example.com/api/user,Charles在DNS层将其指向本地,服务端收到的Host头、Referer头、Origin头全部真实,只是流量被本地截获。实测下来,这是唯一能100%模拟真实网络环境的方案。
第二禁区:Header篡改必须区分“可信Header”与“敏感Header”
哪些Header绝对不能动?Cookie、Authorization、X-Requested-With。动了Cookie,登录态丢失;动了Authorization,JWT校验失败;动了X-Requested-With,后端可能拒绝非AJAX请求。但有些Header必须改:比如金融接口要求X-App-Version: 3.2.1,而你本地版本是3.3.0,不改就会被限流。
安全改法:在Charles的“Rewrite”规则里,只针对特定URL路径启用Header修改。例如,仅对/api/trade/开头的请求,添加X-App-Version: 3.2.1,其他请求保持原样。同时,所有Header修改操作必须记录在团队Wiki里,标注“此Header为模拟旧版本客户端所必需,上线前必须删除”。我们曾因忘记删这条规则,导致灰度发布时部分用户被识别为旧版,触发了错误的降级策略。
第三禁区:Body注入必须严格遵循Content-Type语义
很多人直接在Charles里编辑Request Body,把{"amount":100}改成{"amount":99999},结果接口返回400。原因很简单:如果原始请求Header是Content-Type: application/json,你改Body没问题;但如果Header是Content-Type: application/x-www-form-urlencoded,你却用JSON格式编辑,后端解析必然失败。
铁律操作:在Charles的“Breakpoint”模式下,右键点击请求 → “Edit Request” → 切换到“Headers”标签页,确认Content-Type值;再切换到“Body”标签页,根据类型选择编辑方式:JSON用“JSON”视图,Form用“Form”视图,Raw用“Raw”视图。我们团队强制规定:所有Body修改必须截图存档,包含Headers截图和Body编辑界面截图,作为联调报告附件。这看似繁琐,但避免了“明明改了数据却说没生效”的扯皮。
3.2 断点拦截的黄金四象限:何时该断、断在哪、断后做什么、断后如何放行
断点不是越多越好,而是要精准打击关键决策点。我们总结出HTTP生命周期的四个黄金断点位置,每个位置对应不同的调试目标:
| 断点位置 | 触发时机 | 典型调试目标 | 操作建议 | 风险提示 |
|---|---|---|---|---|
| Request Headers | 请求发出前,Headers已组装完成 | 检查认证Token是否有效、Host是否正确、自定义Header是否缺失 | 查看Authorization值是否为JWT且未过期;核对Host是否为预期域名;确认X-Trace-ID是否生成 | 不要在此处修改Headers后直接放行,可能破坏签名逻辑 |
| Request Body | 请求发出前,Body已序列化 | 验证提交数据格式、边界值、敏感字段脱敏 | 检查amount是否为数字而非字符串;确认phone字段是否已脱敏为138****1234;验证file字段是否为Blob对象 | 修改Body后务必重新计算Content-Length,否则后端接收不全 |
| Response Headers | 响应返回后,Headers已接收 | 分析缓存策略、重定向跳转、错误码含义 | 查看Cache-Control是否为no-cache;确认Location头是否指向正确URL;解读X-RateLimit-Remaining剩余调用次数 | 此处修改Headers可能导致前端缓存异常,仅用于临时测试 |
| Response Body | 响应返回后,Body已接收但未解析 | 修复数据格式、注入测试字段、模拟异常结构 | 将{"code":0,"data":{}}改为{"code":500,"msg":"mock error"};在data里添加__mock_timestamp: Date.now()便于追踪;把空数组[]改为[{"id":1,"name":"test"}] | 修改Body后需确保JSON语法正确,否则前端JSON.parse()报错 |
实操心得:不要依赖“自动断点”。比如想测试“接口超时”,很多人在Response Body断点,然后手动延迟。这是错的——超时发生在TCP连接建立或响应头接收阶段,Body断点时连接早已建立。正确做法是:在Charles里配置“Throttle”(限速),将网络设为“GPRS”,此时请求自然超时,你能在Network面板看到Failed to load response data,这才是真实超时场景。同样,“401未授权”测试,应该在Request Headers断点,删除Authorization头后放行,而不是在Response Body里伪造401响应——前者能触发前端真实的登录态失效流程,后者只是个静态错误页。
3.3 Mock规则编写的反直觉原则:状态驱动优于数据驱动,副作用最小化
新手写Mock规则,本能是“我要返回什么数据”,比如return { code: 0, data: { balance: 10000 } }。这会导致两个问题:一是规则和业务逻辑耦合,二是无法模拟真实服务的副作用(如扣款后余额变更、下单后库存减少)。我们推行“状态驱动”规则,即规则描述的是系统当前状态,而非静态数据。
案例:股票委托单状态机模拟
真实场景中,委托单有“已报”、“部成”、“已成”、“已撤”、“废单”五种状态,且状态流转受时间、价格、市场状态影响。如果写五个静态JSON,测试覆盖率极低。我们用MSW编写如下规则:
// 模拟委托单查询接口 rest.get('/api/order/:orderId', (req, res, ctx) => { const orderId = req.params.orderId; // 从内存状态机获取当前订单状态 const orderState = getOrderState(orderId); // 状态机函数,根据orderId返回状态 // 根据状态返回不同结构 switch(orderState) { case 'SUBMITTED': return res( ctx.status(200), ctx.json({ code: 0, data: { orderId, status: 'SUBMITTED', submitTime: Date.now() - 60000, // 1分钟前提交 price: 10.5, volume: 1000 } }) ); case 'PARTIAL_FILLED': return res( ctx.status(200), ctx.json({ code: 0, data: { orderId, status: 'PARTIAL_FILLED', submitTime: Date.now() - 120000, fillTime: Date.now() - 30000, // 30秒前部分成交 price: 10.5, volume: 1000, filledVolume: 300, // 已成交300股 avgFillPrice: 10.48 } }) ); // ... 其他状态 } });关键点:getOrderState()是一个可配置的内存状态机,我们提供CLI命令mock-state set-order-status 12345 PARTIAL_FILLED,测试时一键切换状态,无需重启服务。这比写十个JSON文件高效十倍。
副作用最小化原则:Mock规则里禁止任何外部I/O操作。曾有同事在规则里调用fs.readFileSync('./config.json')读取配置,导致每次请求都触发磁盘IO,页面加载慢3秒。正确做法是启动时一次性读取配置到内存,规则里只做纯函数计算。我们约定:所有Mock规则函数必须是无副作用、确定性、可缓存的。这意味着同一个请求参数,永远返回相同响应(除非你主动修改状态机)。
4. 实操过程:从零搭建可交付的Mock联调环境
4.1 环境准备:三件套安装与基础配置(10分钟搞定)
第一步:Charles安装与HTTPS抓包配置
下载Charles Proxy(官网正版,避免破解版证书风险),安装后打开。关键配置有三处:
- SSL Proxying:菜单栏
Proxy → SSL Proxying Settings,勾选Enable SSL Proxying,在Locations里添加*(通配所有域名)。这是为了抓取HTTPS请求,但必须配合下一步证书安装; - Install Charles Root Certificate:菜单栏
Help → SSL Proxying → Install Charles Root Certificate,按向导安装到系统钥匙串,并在钥匙串里双击证书 → “信任” → “始终信任”。这一步漏掉,所有HTTPS请求会显示SSL handshake failed; - Local Proxy Port:菜单栏
Proxy → Proxy Settings,确认端口为8888(默认),这是后续所有工具对接的端口。
提示:如果公司电脑管理员禁用了证书安装,可用浏览器DevTools的Network面板替代Charles,但会失去Host重写能力。此时必须用Webpack DevServer代理,配置
proxy: { '/api': { target: 'http://localhost:3000', changeOrigin: true } },代价是每次改代理都要重启服务。
第二步:MSW初始化与Vite集成
我们以Vite + Vue3 + TypeScript项目为例(其他框架同理):
# 1. 安装MSW npm install -D msw # 2. 创建mocks/handlers.ts,定义基础规则 import { rest } from 'msw' export const handlers = [ rest.get('/api/user/profile', (req, res, ctx) => { return res(ctx.status(200), ctx.json({ code: 0, data: { name: 'Mock User', balance: 10000 } })) }), ]// 3. 创建mocks/browser.ts,浏览器端启动入口 import { setupWorker } from 'msw' import { handlers } from './handlers' export const worker = setupWorker(...handlers)// 4. 在src/main.ts最顶部引入(必须在app.mount前) import { worker } from './mocks/browser' if (process.env.NODE_ENV === 'development') { worker.start({ onUnhandledRequest: 'bypass' // 未匹配规则的请求放行给真实服务器 }) }关键验证:启动Vite服务后,打开浏览器DevTools → Application → Service Workers,能看到MSW注册成功;Network面板里所有/api/请求的Size列会显示(from service worker),证明MSW已接管。
第三步:VS Code调试配置(可选但强烈推荐)
在项目根目录创建.vscode/launch.json:
{ "version": "0.2.0", "configurations": [ { "type": "pwa-chrome", "request": "launch", "name": "Launch Chrome with Mock", "url": "http://localhost:5173", "webRoot": "${workspaceFolder}", "sourceMaps": true, "trace": true, "runtimeArgs": [ "--remote-debugging-port=9222", "--proxy-server=localhost:8888", // 关键!让Chrome走Charles代理 "--proxy-bypass-list=<-loopback>" ] } ] }这样F5启动后,Chrome自动走Charles代理,无需手动设置浏览器代理。我们团队所有成员都用此配置,统一环境。
4.2 规则改写实战:金融行情接口的动态重写链
以一个真实金融项目为例:生产环境行情接口为wss://quote-prod.example.com/ws(WebSocket),REST接口为https://api-prod.example.com/v1/quote。前端代码里硬编码了api-prod.example.com,但我们希望:
- 开发时,所有
api-prod.example.com请求重写为本地Mock; - 测试时,部分请求(如
/v1/quote/stock)仍走真实环境,只Mock/v1/quote/fund; - 上线前,一键关闭所有Mock,回归真实环境。
Charles配置步骤:
Proxy → Recording Settings,勾选Record HTTP Headers和Record HTTPS Headers,确保能查看完整请求;Tools → Map Remote,点击Add:Source Host:api-prod.example.comSource Port:443Destination Host:localhostDestination Port:3000Protocol:HTTPS- 勾选
Enable Map Remote;
Tools → Rewrite,点击Add新建规则组,命名为Finance API Rewrite:- 添加规则:
If URL matches /v1/quote/fund.*→Then Set URL to http://localhost:3000/mock/quote/fund; - 添加规则:
If URL matches /v1/quote/stock.*→Then Do nothing(即放行); - 勾选
Enable Rewrite Rules。
- 添加规则:
MSW规则增强:
仅重写URL不够,金融接口常需动态响应。我们在mocks/handlers.ts里添加:
// 模拟基金净值查询,支持按日期回溯 rest.get('/mock/quote/fund/:fundCode', (req, res, ctx) => { const fundCode = req.params.fundCode const date = req.url.searchParams.get('date') || '2024-01-01' // 根据基金代码和日期返回不同净值 const navData = { '000001': { '2024-01-01': 1.2345, '2024-01-02': 1.2367 }, '110011': { '2024-01-01': 0.9876, '2024-01-02': 0.9891 } } const nav = navData[fundCode]?.[date] || 1.0 return res( ctx.status(200), ctx.json({ code: 0, data: { fundCode, nav, date, updateTime: new Date().toISOString() } }) ) })效果验证:
- 访问
https://api-prod.example.com/v1/quote/fund/000001?date=2024-01-01→ 返回Mock数据; - 访问
https://api-prod.example.com/v1/quote/stock/600519→ 返回真实行情; - 在Charles的
Structure标签页,能看到api-prod.example.com节点下,/v1/quote/fund请求显示绿色Mapped,/v1/quote/stock显示灰色Bypassed。
这套配置,让开发、测试、预发环境共用同一套规则,只需开关Charles的Map Remote即可切换,彻底告别process.env.VUE_APP_API_BASE_URL的环境变量地狱。
4.3 断点拦截全流程:从发现Bug到修复验证的5分钟闭环
以一个高频Bug为例:“用户在交易时段内提交买入委托,页面显示‘下单成功’,但实际未成交,后台无记录”。传统排查要等后端查日志,至少半小时。用断点拦截,5分钟闭环:
Step 1:复现并定位请求
- 打开Chrome DevTools → Network面板;
- 操作页面触发下单,找到
POST /api/order/submit请求; - 右键 →
Break on fetch/XHR,刷新页面,请求自动暂停在Request Headers断点;
Step 2:检查请求完整性
- 在
Headers标签页,确认:Authorization值存在且格式为Bearer xxx;Content-Type: application/json;X-Trade-Session: 20240101001(交易会话ID)存在;
- 切换到
Payload标签页,确认Body为:{"symbol":"600519","side":"BUY","price":1900.00,"volume":100,"orderType":"LIMIT"}注意:这里发现
price是1900.00,但当前股价是1899.50,限价单合理。
Step 3:拦截响应并注入调试字段
- 在Charles里,对
/api/order/submit设置Break on Response; - 重新触发下单,请求走到Response断点;
- 在Charles的
Response标签页,点击Edit Response→Body→JSON视图; - 在
data对象里添加__debug_info: { receivedAt: Date.now(), serverIP: '10.0.1.100' }; - 点击
Execute放行;
Step 4:前端验证与日志输出
- 在前端代码里,
fetch后添加:.then(res => res.json()) .then(data => { console.log('Debug Info:', data.__debug_info) // 输出服务器IP和接收时间 if (data.code !== 0) { throw new Error(data.msg) } }) - 刷新页面,Console里看到
Debug Info: {receivedAt: 1704067200000, serverIP: "10.0.1.100"},证明请求确实到达了后端集群的10.0.1.100节点;
Step 5:结论与协作
- 既然请求已送达且返回成功,问题不在网络层,而在后端业务逻辑;
- 将
serverIP和receivedAt时间戳提供给后端,他们可在该节点日志里精确搜索; - 同时,我们用MSW规则模拟该节点故障:
这样,前端可立即复现问题,无需等待后端修复。rest.post('/api/order/submit', (req, res, ctx) => { // 模拟节点10.0.1.100在特定时间返回空响应 if (req.url.searchParams.get('debug_ip') === '10.0.1.100') { return res(ctx.status(200), ctx.json({ code: 0, data: {} })) // 空data触发前端异常 } })
整个过程,没有一次后端沟通,前端自主定位到根因。这就是断点拦截赋予的生产力。
5. 常见问题与排查技巧实录:那些年踩过的坑和省下的时间
5.1 “Mock数据不生效”问题速查表(90%的问题在这里)
| 现象 | 可能原因 | 排查步骤 | 解决方案 | 经验备注 |
|---|---|---|---|---|
Network面板显示(from service worker)但返回404 | MSW规则路径与请求URL不匹配,大小写或斜杠不一致 | 1. 查看Network面板请求URL(如/api/user/profile)2. 检查MSW规则 rest.get('/api/user/profile', ...)是否完全一致3. 在MSW控制台查看 [MSW] Warning: captured a request without a matching request handler | 确保规则路径与请求URL逐字符匹配;开启onUnhandledRequest: 'warn'获取详细日志 | 我们团队约定:所有API路径在Swagger里定义后,直接复制到MSW规则,避免手写错误 |
Charles显示SSL handshake failed | 系统证书未正确安装或未设为“始终信任” | 1. 打开钥匙串访问 → 登录 → 证书类别 → 查找Charles Proxy CA2. 双击证书 → 信任 → “始终信任” 3. 重启Charles | 重新安装证书,务必在钥匙串里设置“始终信任” | macOS Ventura后,系统对证书要求更严,必须手动设置,不能只点“信任” |
| Mock数据生效,但页面报跨域错误 | 前端代码里fetch使用了credentials: 'include',但Mock Server未设置CORS | 1. 查看Network面板响应Headers,确认是否有Access-Control-Allow-Origin: *2. 查看MSW文档,确认是否配置了 ctx.set('Access-Control-Allow-Origin', '*') | 在MSW规则里添加ctx.set('Access-Control-Allow-Origin', '*')和ctx.set('Access-Control-Allow-Credentials', 'true') | MSW默认不加CORS头,必须显式设置,否则带Cookie的请求会失败 |
| 规则改写后,页面样式错乱或JS报错 | Charles重写了HTML/CSS/JS资源,导致文件损坏 | 1. 在Charles的Structure面板,展开api-prod.example.com节点2. 查看是否有 /static/js/app.js等非API请求被重写3. 在 Map Remote设置里,添加Exclude规则:*.js, *.css, *.png, *.jpg | 在Map Remote设置里,勾选Exclude,添加常见静态资源后缀 | 金融项目常有/static/chart.min.js等资源,重写后JS语法错误,页面白屏 |
5.2 规则改写进阶避坑:那些让你加班到凌晨的隐藏雷区
雷区一:Host重写与Cookie域冲突
现象:登录后,Mock接口返回401。排查发现,Set-Cookie的Domain是.example.com,但Charles重写Host为localhost,浏览器认为localhost不属于.example.com,拒绝存储Cookie。
解决方案:在Charles的Rewrite规则里,对Set-CookieHeader做二次处理:
- 添加规则:
If Header Name is Set-Cookie and Value contains Domain=.example.com→Then Replace Value Domain=.example.com with Domain=localhost; - 或更彻底:在MSW规则里,不依赖Cookie鉴权,改用
Authorization: Bearer xxx,前端统一管理Token。
雷区二:WebSocket重写后连接失败
现象:wss://quote-prod.example.com/ws重写为ws://localhost:3000/ws后,连接报错Error during WebSocket handshake: net::ERR_CONNECTION_REFUSED。
原因:WebSocket协议升级需要Upgrade: websocket和Connection: UpgradeHeader,Charles默认不转发这些Header。
解决方案:在Charles的Proxy → SSL Proxying Settings → Locations里,添加wss://quote-prod.example.com,并勾选Enable SSL Proxying;同时在Rewrite规则里,确保Upgrade和ConnectionHeader被透传。
雷区三:断点拦截导致页面卡死
现象:设置Break on Response后,页面长时间白屏,Console无报错。
原因:某些金融接口返回超大JSON(如全市场行情快照,2MB+),Charles断点时加载整个Body到内存,浏览器卡死。
解决方案:在Charles的Proxy → Recording Settings里,勾选Limit recording to,设置1024 KB,超过大小的响应自动截断;或改用Break on Headers,只检查状态码和Headers,不加载Body。
5.3 断点拦截独家技巧:提升10倍效率的冷知识
技巧一:用console.table()可视化请求参数
在Chrome DevTools Console里,粘贴以下代码,可一键打印当前所有XHR请求的URL、Method、Headers:
// 获取所有已发送的XHR请求(需在Network面板开启录制) const requests = performance.getEntriesByType('resource').filter(e => e.name.includes('api/')); console.table(requests.map(r => ({ url: r.name, method: r.initiatorType, size: r.encodedBodySize, duration: r.duration.toFixed(2) })));这比手动翻Network面板快10倍,特别适合排查“哪个接口拖慢了首屏”。
技巧二:Charles断点自动注入调试Header
在Charles的`Tools → Breakpoints