直接用 route。它支持拦截请求并同步返回伪造响应,适合 mock JSON 数据;route_from_har 仅回放录制流量,不灵活且难动态构造数据。

Playwright 中 mock 接口用 route 还是 route_from_har?
直接用 route。它支持拦截请求并同步返回伪造响应,适合 mock JSON 数据;route_from_har 是回放录制流量,不灵活,也不便于动态构造数据。
关键点:mock 必须在页面创建前或导航前注册,否则可能错过首屏请求。
-
page.route()只对当前page生效,新开 tab 或 iframe 需单独处理 - 匹配路径推荐用正则(如
r"/api/user.*"),避免硬编码 query 参数导致漏匹配 - 若需 mock 多个接口,建议集中写在
page.route()回调里用 if/elif 分支,别反复调用route()
如何用 route 返回自定义 JSON 并控制状态码和 header?
核心是调用 route.fulfill(),不是 continue() 或 abort()。它能完全接管响应体、状态码、headers。
示例:mock 用户列表接口返回 200 + 自定义 JSON:
page.route("**/api/users", lambda route: route.fulfill(
status=200,
content_type="application/json",
body='{"data": [{"id": 1, "name": "Alice"}], "total": 1}'
))
-
content_type必须显式设为"application/json",否则前端response.json()可能抛Unexpected token -
body要是字符串,不是 dict —— 别直接传{...},得先json.dumps(...) - 若需 mock 错误场景,把
status改成401或500即可,前端能真实触发错误分支
为什么 mock 后前端仍报 CORS 或 Network Error?
常见原因是没匹配到请求 —— Playwright 的路由匹配基于完整 URL(含 protocol 和 domain),而前端发的请求可能是相对路径或带 base URL。
- 优先用通配符
"**/api/...",而不是"https://example.com/api/...",避免协议或域名差异 - 检查浏览器 DevTools 的 Network 面板,确认实际发出的请求 URL 和你写的 pattern 是否一致
- 如果页面用
fetch且带credentials: "include",mock 响应里要加headers={"Access-Control-Allow-Origin": "*"},否则浏览器会拦截响应体 - 确保没其他
route规则提前匹配并continue()了该请求 —— 路由按注册顺序匹配,越靠前越优先
mock 复杂逻辑(如根据 query 参数返回不同数据)怎么写?
直接在 route 回调里解析 route.request.url 或 route.request.post_data_json,再动态生成响应。
示例:根据 ?role=admin 返回不同用户列表:
page.route("**/api/users", lambda route: (
route.fulfill(status=200, body=json.dumps({"users": [{"name": "Admin"}]}))
if "role=admin" in route.request.url
else route.fulfill(status=200, body=json.dumps({"users": [{"name": "User"}]}))
))
- 注意:不能在 fulfill 前访问
route.request.post_data_json(会触发读取 body,影响后续使用),GET 请求用url更安全 - 复杂条件建议拆成独立函数,避免回调里堆逻辑;但函数内不能 await,
fulfill()是同步 API - 如果需要异步生成数据(比如查本地文件),得提前加载好,或改用
route.continue_()+ 拦截响应(更重,一般没必要)
Playwright 的接口 mock 看似简单,但实际容易卡在匹配失败或响应格式不对上。最常被忽略的是:body 必须是字符串、content_type 必须显式声明、以及路由注册时机必须早于页面发起请求。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











