news 2026/9/7 19:02:11

Playwright 请求 Mock 实战:使用 playwright-cli 拦截、伪造、修改与阻断网络请求

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Playwright 请求 Mock 实战:使用 playwright-cli 拦截、伪造、修改与阻断网络请求

Playwright 请求 Mock 实战:使用 playwright-cli 拦截、伪造、修改与阻断网络请求

【免费下载链接】playwrightPlaywright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.项目地址: https://gitcode.com/GitHub_Trending/pl/playwright

导读

在 Web 开发与测试中,接口尚未就绪、需要模拟异常场景、或想在真实响应上做小改动,都是最常见的诉求。本篇文章围绕当前仓库中playwright-cli技能文档 request-mocking.md 展开,完整讲解 Playwright CLI 模式下如何用一条命令对页面网络流量进行"拦截、Mock、修改与阻断"。读完你不仅能熟练使用route/route-list/unroute命令,还能借助run-code编写条件响应、改写真实响应、模拟断网与延迟等高级拦截逻辑,并理解其底层通过 page/context.route 注册处理器的工作机制。

playwright-cli是一套面向浏览器自动化代理与 LLM Agent 的命令行技能,定义在 SKILL.md,其中网络(Network)类命令属于其能力分类之一。整套技能的安装与调用方式遵循该文件:若全局playwright-cli不可用,可先通过npx playwright cli使用本地版本,或执行npm install -g @playwright/cli@latest安装全局命令。

CLI Route 命令:一条命令搞定最常见 Mock

原文档给出了五类最常用的命令形态,分别覆盖"自定义状态码、JSON Body、自定义请求头、移除请求头、路由的增删查"。下面逐条给出并做参数补充说明。

用自定义状态码模拟失败

playwright-cli route "**/*.jpg" --status=404

命中**/*.jpg的图片请求将不再发往服务器,而是直接返回 404。--status指定 HTTP 状态码,默认值为 200。

用 JSON 文本伪造接口响应

playwright-cli route "**/api/users" --body='[{"id":1,"name":"Alice"}]' --content-type=application/json

--body是响应体(纯文本或 JSON 字符串),建议同时用--content-type显式声明 Content-Type,避免页面端 JSON 解析失败。两个参数都没有被限制为 JSON,因此也可以返回text/htmltext/plain等任意文本。

附加自定义响应头 / 移除请求头

# 响应携带自定义头 playwright-cli route "**/api/data" --body='{"ok":true}' --header="X-Custom: value" # 从实际发出的请求里剥离敏感头(cookie、authorization 等) playwright-cli route "**/*" --remove-header=cookie,authorization

--header使用"Name: Value"格式、可重复传入多条;--remove-header接受逗号分隔的头名列表。注意这两者的语义差别很大:--header作用于Mock 响应的响应头,而--remove-header实际是在放行真实请求前删除该请求的请求头

从源码看,这两种"有 body/status 就 fulfill、否则改头后 continue"的分支逻辑正是 CLI 封装层的关键设计。其声明位于 cli-daemon/commands.ts(route命令的 zod 参数与选项校验),真正的路由处理器实现在 tools/backend/route.ts:

  • 若提供了bodystatus,则调用route.fulfill({ status, contentType, body })直接以 Mock 数据应答,请求不会再到达服务器;
  • 否则,基于route.request().headers()复制当前请求头,叠加--header添加的头、删除--remove-header指定的头(删除时统一按小写键匹配),再通过route.continue({ headers })放行。

--remove-header因此在拦截器场景下很有用:例如想验证"不带 Cookie 访问"或"剔除 Authorization 后是否仍能鉴权"时,不必改应用代码即可模拟。removeHeaders在命令层被定义为一个原始字符串(commands.ts),到 route.ts 内部才按逗号splittrim,所以书写时要确保逗号与名称之间没有多余空格。

查看与移除已注册路由

# 列出当前所有生效路由 playwright-cli route-list # 按模式移除某一条(或一类)路由 playwright-cli unroute "**/*.jpg" # 不带模式参数时移除全部路由 playwright-cli unroute

route-list在命令层被标记为raw: true(commands.ts),其输出逻辑会把每条路由格式化为序号. pattern (status=..., body=..., contentType=..., addHeaders=..., removeHeaders=...),其中 body 超过 50 字符会被截断展示(route.ts)。没有路由时输出No active routes

unroute的匹配基于完全相同的模式字符串:由 context.ts 中的removeRoute(pattern)过滤内部路由表_routes,对每个同名模式调用browserContext.unroute(pattern, handler)精确解绑;省略 pattern 时则遍历清空并返回移除总数。因此与route注册时使用逐字一致的 pattern(包括通配符写法),才能保证命中预期的那条规则。

这些行为都有自动化测试覆盖,见 cli-route.spec.ts,其中验证了:空列表时route-list无输出;注册后route-list显示status=200unroute "**/api/users"恰好移除 1 条而另一条**/api/posts保留;不带参数的unroute提示Removed all 2 route

URL 匹配模式(glob 语法)

route命令的第一个位置参数pattern使用 Playwright 全局匹配语法,本质上是把该 glob 模式交给browserContext.route(pattern, handler)去匹配。文档给出的四类范式如下:

**/api/users - 精确匹配路径段 **/api/*/details - 路径中的单级通配符 **/*.{png,jpg,jpeg} - 按文件扩展名匹配 **/search?q=* - 匹配带查询参数的 URL

要点说明:

  • **匹配任意层级的路径;*在路径段内匹配任意字符;?可匹配单个字符。
  • {png,jpg,jpeg}花括号枚举常用于按资源类型统一拦截,例如**/*.{png,jpg,jpeg}可一次覆盖绝大多数图片格式。
  • pattern 支持拼入查询串(如**/search?q=*),适合只拦截特定参数的请求。
  • 在 commands.ts 中 pattern 被描述为"**/api/users"这类 URL 通配,实际使用时可从"最宽的**"到"尽量窄的具体 URL"按需收敛,规则越具体,误伤越少。

用 run-code 实现高级拦截

route命令覆盖的是"固定响应 / 放行改头"这两种最常见形态。当需要基于请求内容决定响应、改写真实响应、模拟网络故障、引入延迟等按请求动态决策的逻辑时,文档给出了一套统一的进阶手段:playwright-cli run-code,传入一个async page => { ... }函数,在函数体内使用 Playwright 标准的page.routeAPI。它与路由命令共处同一能力体系中,使用方式详见 running-code.md;命令行还支持把脚本写入文件后通过run-code --filename=script.js执行。

根据请求内容返回条件响应

playwright-cli run-code "async page => { await page.route('**/api/login', route => { const body = route.request().postDataJSON(); if (body.username === 'admin') { route.fulfill({ body: JSON.stringify({ token: 'mock-token' }) }); } else { route.fulfill({ status: 401, body: JSON.stringify({ error: 'Invalid' }) }); } }); }"

这里通过route.request().postDataJSON()读取 POST 请求体并反序列化,然后按业务条件分流:管理员账号返回一个伪造的token(状态码默认 200),其他账号则用status: 401模拟鉴权失败。这相当于把上文的静态 Mock 升级为"假后端",非常适合在真实登录服务不可用时驱动整条登录流程的测试。

放行并改写真实响应

playwright-cli run-code "async page => { await page.route('**/api/user', async route => { const response = await route.fetch(); const json = await response.json(); json.isPremium = true; await route.fulfill({ response, json }); }); }"

此模式先用route.fetch()向服务器真实发起请求拿到response,再对响应体做增量修改(示例把isPremium置为true),最后调用route.fulfill({ response, json })原始响应 + 修改后的 JSON 体一同返回给页面。相比--body的整体替换,这种"沿用真实状态码与响应头、只改业务字段"的拦截方式更贴近真实环境,是验证会员权益、折扣价等灰度逻辑时的常用手段。

模拟网络故障与错误码

playwright-cli run-code "async page => { await page.route('**/api/offline', route => route.abort('internetdisconnected')); }" # 可选错误码:connectionrefused, timedout, connectionreset, internetdisconnected

route.abort(errorCode)会直接中断请求并让页面侧收到对应类型的网络错误。文档列出的可用错误码包括connectionrefused(连接被拒)、timedout(超时)、connectionreset(连接被重置)与internetdisconnected(断网)。这为演练页面在弱网、断网、服务不可用时的降级与错误提示提供了零成本复现手段,同时也可借此验证应用是否会把错误信息误暴露给用户。

注入响应延迟

playwright-cli run-code "async page => { await page.route('**/api/slow', async route => { await new Promise(r => setTimeout(r, 3000)); route.fulfill({ body: JSON.stringify({ data: 'loaded' }) }); }); }"

在 handler 中先await一个 3 秒的定时器再fulfill,即可精确制造"慢接口"。通过调节setTimeout的时长,可以复现 loading 态闪现、超时竞态、按钮防重复提交等与响应耗时相关的交互问题。

底层原理:路由如何注册、生效与注销

把 CLI 命令与实现一一对应,可以看清整条链路的全貌:

  1. 参数声明与校验routeroute-listunroute三条 CLI 命令在 cli-daemon/commands.ts 中声明,分别映射到底层工具browser_routebrowser_route_listbrowser_unroute
  2. 处理器构造:tools/backend/route.ts 中browser_route会把 CLI 选项翻译为一条RouteEntry,内含patternstatusbodycontentTypeaddHeadersremoveHeaders以及真正执行拦截/放行的handler闭包。
  3. 注册到浏览器上下文context.addRoute(entry)内部调用browserContext.route(pattern, handler),把处理器挂到 BrowserContext 的网络拦截层,使该浏览器上下文内所有标签页的请求都受此规则影响(context.ts)。
  4. 请求命中后的分派:命中 pattern 的请求进入 handler,按上文所述"有 body/status → fulfill;否则改请求头后 continue"的策略处理。
  5. 查询与清理browser_route_list遍历context.routes()输出明细;unroute则通过context.removeRoute(pattern)精确解绑同名处理器,或全量清空(context.ts)。

值得注意的两点:

  • 路由挂在BrowserContext上而非单个 Page 上(browserContext.route),因此对后续新打开的标签页同样生效;如需"一次性路由",应在高级脚本中改用page.route,其随页面关闭自动失效。
  • 一个 pattern 允许注册多条规则,route-list会逐条编号展示;注册多条相同 pattern 时,unroute pattern会把它们全部移除并返回移除条数(cli-route.spec.ts 对此有对应断言)。

使用建议与注意事项

  • 能静态就不写码:仅需固定状态码、固定 body、固定响应头或删请求头时,优先用route命令;涉及动态判断、真实响应改写、延迟、abort 时才引入run-code,二者对应的正是文档划分的"CLI Route Commands"与"Advanced Mocking with run-code"两层。
  • pattern 一致性unroute是按模式字符串精确匹配的,注销时需与route注册的 pattern 完全一致(参考 context.ts 的过滤逻辑)。
  • 善用route-list排查:忘记自己注册过哪些规则、或响应行为"诡异"时,先执行playwright-cli route-list,观察每条规则的status/contentType/body(超长截断)等详情,再用unroute "pattern"精确摘除,避免 Mock 残留干扰后续操作。
  • Mock 范围注意route系列作用于浏览器上下文,适合整场会话级别的稳定 Mock;若只想在特定页面流程内临时生效,建议使用run-code+page.route并在流程结束时page.unroute主动清理。
  • 命令不可用时:按 SKILL.md 的安装说明,先尝试npx playwright cli,或在具备网络条件下以npm install -g @playwright/cli@latest安装全局命令。

结合 request-mocking.md、commands.ts 与 route.ts 对照阅读,即可在动手时快速定位"某条命令背后到底做了什么",把请求 Mock 从"试出来的技巧"变成可预测、可排查的工程能力。

【免费下载链接】playwrightPlaywright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.项目地址: https://gitcode.com/GitHub_Trending/pl/playwright

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 19:00:24

从代码托管到研发协作,Gitee如何成为企业项目管理新标杆

这几年做技术管理和团队协作,我越来越觉得,工具选得好不好,直接决定一个团队能不能把事做成。Gitee这个平台,我从个人项目存代码,到带着团队做私有化项目管理,再到帮客户搭企业级研发协同方案,几…

作者头像 李华
网站建设 2026/9/7 19:00:02

单片机计算机毕设之基于 STM32 的多传感器室内环境监测与声光报警系统设计 基于 STM32 的手动自动双模式环境监控平台设计与实现(010307)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华
网站建设 2026/9/7 18:56:41

小说人设总崩?从设定到剧情一致性的管理方法

"主角写着写着变了一个人"——这是长篇写作最常见的翻车现场。开篇冷静理智的主角,写到五十章突然无脑冲动;配角前期的重要性格,后文完全消失。人设崩塌的本质不是"你不会写人物",而是"你没管好人物设定…

作者头像 李华
网站建设 2026/9/7 18:55:45

数据库方向考研调剂全攻略:从信息解读到技术准备与导师沟通

每年三四月份调剂系统开放前后,各种招生信息在考研群和导师朋友圈里刷屏。我自己当年也经历过那种感觉:一边盯着研招网,一边翻遍导师主页和课题组论文,连一条调剂通知里的措辞都要反复琢磨好几遍。回头再看,调剂这件事…

作者头像 李华