Playwright实战:模拟和修改网络请求

简介

Playwright 提供强大的 API,可以模拟和修改 HTTP/HTTPS 网络流量。无论是 XHR 还是 fetch 请求,都可以被轻松跟踪、修改和模拟。此外,Playwright 还支持使用 HTTP Archive (HAR) 文件来模拟页面发出的多个网络请求。

模拟 API 请求

以下代码示例展示了如何使用 Playwright 拦截对特定 API 的调用,并返回自定义响应。

def test_mock_the_fruit_api(page: Page):
    def handle(route: Route):
        json = [{"name": "Strawberry", "id": 21}]
        # 使用模拟数据完成路由
        route.fulfill(json=json)
 
    # 拦截到fruits API 的路由
    page.route("*/**/api/v1/fruits", handle)
    # 转到页面
    page.goto("https://demo.playwright.dev/api-mocking")
    # 断言Strawberry可见
    expect(page.get_by_text("Strawberry")).to_be_visible()

在此示例中,我们拦截了对 /api/v1/fruits 的所有调用,并返回一个包含草莓数据的 JSON 响应。测试过程中,页面将使用模拟数据,而不会实际调用 API

修改 API 响应

有时,我们需要发出 API 请求,但希望修改其响应以实现可重现的测试。以下示例展示了如何在拦截请求后,向原始响应中添加新数据。

def test_gets_the_json_from_api_and_adds_a_new_fruit(page: Page):
    def handle(route: Route):
        response = route.fetch()
        json = response.json()
        json.append({"name": "Loquat", "id": 100})
        # 使用原始响应(同时用给定的 JSON 对象修补响应体)来完成
        route.fulfill(response=response, json=json)
 
    page.route("https://demo.playwright.dev/api-mocking/api/v1/fruits", handle)
    # 转到页面
    page.goto("https://demo.playwright.dev/api-mocking")
    # 断言Loquat可见
    expect(page.get_by_text("Loquat", exact=True)).to_be_visible()

在此示例中,拦截了对水果 API 的调用,并向返回的数据中添加了一个名为 ‘Loquat’ 的新水果。然后,验证该数据是否在页面上正确显示

在这里插入图片描述

通过检查响应,可以看到Loquat已添加到列表中。

在这里插入图片描述

使用 HAR 文件进行模拟

HAR 文件记录了加载页面时发出的所有网络请求。使用 Playwright,我们可以录制、修改和重放这些请求。

记录 HAR 文件

要记录 HAR 文件,可以使用 page.route_from_har()browser_context.route_from_har() 方法。以下示例展示了如何录制 HAR 文件并使用实际数据更新它。

def test_records_or_updates_the_har_file(page: Page):
    # 从 HAR 文件获取响应
    page.route_from_har("./hars/fruit.har", url="*/**/api/v1/fruits", update=True)
    # 转到页面
    page.goto("https://demo.playwright.dev/api-mocking")
    # 断言Strawberry可见
    expect(page.get_by_text("Strawberry")).to_be_visible()

修改 HAR 文件

录制完 HAR 文件后,可以手动编辑其中的 JSON 数据。例如,可以添加新的水果数据。

[
  {
    "name": "Playwright",
    "id": 100
  },
  // ... other fruits
]

从 HAR 重放

修改完 HAR 文件后,可以在测试中使用它来提供匹配的响应。以下示例展示了如何从 HAR 文件重放 API 请求。

def test_gets_the_json_from_har_and_checks_the_new_fruit_has_been_added(page: Page):
    # 从 HAR 重放 API 请求。
    # 要么使用 HAR 中的匹配响应,
    # 要么如果没有匹配项则中止请求。
    page.route_from_har("./hars/fruit.har", url="*/**/api/v1/fruits", update=False)
    # 转到页面
    page.goto("https://demo.playwright.dev/api-mocking")
    # 断言 Playwright 可见
    expect(page.get_by_text("Playwright", exact=True)).to_be_visible()

在此示例中,测试从 HAR 文件获取响应,而不会实际调用 API。我们验证了新添加的水果数据是否在页面上正确显示。

在这里插入图片描述
在这里插入图片描述

使用 CLI 录制 HAR

除了使用代码录制 HAR 文件外,还可以使用 Playwright CLI。以下命令展示了如何录制特定 API 请求的 HAR 文件。

# 将example.com的API请求保存为“example.har”存档。
playwright open --save-har=example.har --save-har-glob="**/api/**" https://example.com

模拟 WebSocket

Playwright 还支持模拟 WebSocket 通信。以下示例展示了如何拦截 WebSocket 连接并模拟整个通信过程。

def message_handler(ws: WebSocketRoute, message: Union[str, bytes]):
  if message == "request":
    ws.send("response")

page.route_web_socket("wss://example.com/ws", lambda ws: ws.on_message(
    lambda message: message_handler(ws, message)
))

或者,我们可以连接到实际服务器,但拦截并修改中间的消息。以下示例展示了如何实现这一点。

def message_handler(server: WebSocketRoute, message: Union[str, bytes]):
  if message == "request":
    server.send("request2")
  else:
    server.send(message)

def handler(ws: WebSocketRoute):
  server = ws.connect_to_server()
  ws.on_message(lambda message: message_handler(server, message))

page.route_web_socket("wss://example.com/ws", handler)
### 使用 Playwright Java 发送 POST 请求 为了通过 Playwright Java 发送 POST 请求,可以利用 `APIRequestContext` 类来创建 API 请求上下文,并调用相应的 URL 资源。下面是一个完整的例子展示如何配置并执行一个 POST 请求: ```java import com.microsoft.playwright.APIRequest; import com.microsoft.playwright.APIRequestContext; import com.microsoft.playwright.Playwright; public class PostExample { public static void main(String[] args) { try (Playwright playwright = Playwright.create()) { APIRequest apiRequest = playwright.api(); // 创建一个新的 API 请求上下文 APIRequest.NewApiRequestContextOptions options = new APIRequest.NewApiRequestContextOptions() .setExtraHTTPHeaders(Map.of( "Content-Type", "application/json", "User-Agent", "Mozilla/5.0" )); try (APIRequestContext context = apiRequest.newContext(options)) { String payload = "{ \"key1\": \"value1\", \"key2\": \"value2\" }"; // 执行 POST 请求 context.post("https://example.com/api/resource", new APIRequestContext.PostOptions().setData(payload)); } } } } ``` 上述代码展示了设置额外 HTTP 头部信息的重要性[^1],这有助于模拟合法浏览器行为。同时,在构建请求体时需要注意目标服务器所期望的数据格式。 #### 配置选项说明 - **extraHTTPHeaders**: 设置自定义头部字段,如 Content-Type User-Agent 来模仿真实的浏览器访问。 - **data**: 提交的内容作为字符串形式传递给服务器端资源。 此方法允许开发者轻松地向指定的目标地址发起带有有效负载的 POST 请求,并处理可能发生的异常情况以确保程序稳定运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值