目录 (Outline)
- 一、 超越 UI 调试:为什么我们需要编程控制浏览器?
- 二、 CDP 协议核心:Network 域与 Fetch 域
- 三、 实战 1:利用 CDP 模拟「极度弱网」与「离线」场景
- 四、 实战 2:精细化的请求拦截与 Response Mock
- 五、 自动化测试集成:Puppeteer 与 Playwright 的 CDP 接口
- 六、 性能监控进阶:通过 CDP 获取未被压缩的资源大小
- 七、 总结:掌握浏览器底层控制的「金钥匙」
一、 超越 UI 调试:为什么我们需要编程控制浏览器?
1. 痛点:手动模拟的局限性
在 Chrome DevTools 的 Network 面板里,虽然可以设置「Fast 3G」或「Slow 3G」,但它是全局的。
2. 自动化需求
在 CI/CD 流程中,我们需要自动测试:
- 弱网环境下首页加载是否超时?
- 接口返回 500 时,前端是否显示了正确的错误状态?
- 模拟特定域名下的资源加载失败。
这些都需要通过编程手段来实现。
二、 CDP 协议核心:Network 域与 Fetch 域
CDP 是浏览器内部的一种通信协议。在网络控制方面,有两个核心域:
- Network 域:负责监听请求信息、模拟网络状况(带宽、延迟)。
- Fetch 域:负责拦截、修改请求和响应。
三、 实战 1:利用 CDP 模拟「极度弱网」与「离线」场景
使用 Puppeteer 开启 CDP 会话。
代码实现
const client = await page.target().createCDPSession();
// 开启 Network 域
await client.send('Network.enable');
// 模拟极度弱网 (Slow 2G 级别)
await client.send('Network.emulateNetworkConditions', {
offline: false,
latency: 2000, // 2秒延迟
downloadThroughput: 50 * 1024 / 8, // 50kbps
uploadThroughput: 20 * 1024 / 8, // 20kbps
});
// 如果要模拟离线
// await client.send('Network.emulateNetworkConditions', { offline: true, ... });
四、 实战 2:精细化的请求拦截与 Response Mock
相比于全局代理,Fetch.enable 允许我们根据正则表达式精准拦截特定请求。
实现步骤
- 监听请求:
await client.send('Fetch.enable', { patterns: [{ urlPattern: '*/api/user/*', requestStage: 'Request' }] }); - 修改响应:
client.on('Fetch.requestPaused', async (event) => { // 拦截到请求,直接返回自定义数据 await client.send('Fetch.fulfillRequest', { requestId: event.requestId, responseCode: 200, responseHeaders: [{ name: 'Content-Type', value: 'application/json' }], body: Buffer.from(JSON.stringify({ name: 'Mocked User' })).toString('base64'), }); });
五、 自动化测试集成:Puppeteer 与 Playwright 的 CDP 接口
虽然 Puppeteer 和 Playwright 都提供了更高级的 page.route 封装,但在某些极端场景(如处理 Service Worker 拦截的请求、或修改底层 TCP 参数)下,直接调用 CDPSession 依然是不可替代的。
六、 性能监控进阶:通过 CDP 获取未被压缩的资源大小
有时候我们需要知道资源在 Gzip/Brotli 压缩前的原始大小,以进行更精准的包体积优化。
await client.send('Network.getResponseBody', { requestId });
// 这将返回解码后的内容
七、 总结:掌握浏览器底层控制的「金钥匙」
CDP 不仅仅是调试工具,它更像是一把「金钥匙」,让我们能够穿透浏览器的高级封装,直接操控底层引擎。掌握了 CDP,你就具备了构建复杂自动化测试框架、性能分析工具甚至自研浏览器的基础能力。