WebDriver BiDi: 如何获取网络请求和响应体?
2025-01-23 06:08:57
WebDriver BiDi:获取请求和响应体
使用WebDriver BiDi监听网络事件时,获取请求和响应体是一项常见的需求,这对于调试和自动化测试至关重要。 本文探讨如何有效地捕获 BeforeRequestSent
和 ResponseDetails
事件中的请求体和响应体。
理解事件数据结构
BeforeRequestSent
和 ResponseDetails
事件提供关于网络活动的关键信息, 但并非直接包含请求体和响应体的完整数据。BeforeRequestSent
事件主要关注请求的初始化,包括 URL,方法,headers, 并没有请求体的原始字节序列或JSON形式。同样,ResponseDetails
事件提供了响应头和状态码等,也没有包含响应体的完整内容。
问题的核心在于,BeforeRequestSent
和 ResponseDetails
事件设计为传递轻量级信息,如果包含完整的 body 内容,会降低性能并产生大量的流量。 你需要主动要求 WebDriver 获取这些body 内容。
获取请求体
network.onBeforeRequestSent
事件触发时,若需要请求体,需要使用 Network.getResponseBody
命令(对应 BiDi 的 network.getResponseBody
)。 需要 requestId
参数 。这个请求ID 来源于请求信息中,并且对应当前需要获取的body体的请求ID 。
- 原理:这个命令告诉浏览器,要提取这个
requestId
对应请求的body 体。它返回的是一个可能为空的base64
编码字符串, 如果存在。 - 示例(Java)
import org.openqa.selenium.WebDriver; import org.openqa.selenium.bidi.Network; import org.openqa.selenium.bidi.network.BeforeRequestSent; import org.openqa.selenium.bidi.network.ResponseDetails; public class BidiNetworkMonitor { public static void main(String[] args) { // 使用你选择的浏览器驱动 WebDriver driver = WebDriverHelper.getChromeDriver(); Network network = ((HasDevTools) driver).getDevTools().getDomains().network(); network.onBeforeRequestSent(request -> { System.out.println("Request URL: " + request.getRequest().getUrl()); network.getRequestBody(request.getRequest().getRequestId()).thenAccept(body -> { if(body.isPresent()){ System.out.println("Request body:" + body.get().text); } }); }); //加载测试页面或进行相关操作 driver.get("https://postman-echo.com/post"); // 防止进程退出 try{Thread.sleep(5000);} catch (InterruptedException e){ e.printStackTrace(); } driver.quit(); } }
- 步骤:
- 初始化 WebDriver 实例。
- 获取
Network
监听器。 - 为
onBeforeRequestSent
设置回调函数,每次收到请求都执行. - 通过
request.getRequest().getRequestId()
获取到当前请求的id - 调用
network.getRequestBody()
获取 body 信息 - 对返回结果进行判断处理, 如果
body.isPresent()
说明请求有body 数据
- 注意事项:
- 需要确保使用的 WebDriver 版本支持
getRequestBody
命令 - 请求体可能是多种格式 (text, json, xml etc),需要在代码中做处理
Network.getRequestBody()
可能返回空 Optional 对象,此时,你需要额外的检查逻辑
- 需要确保使用的 WebDriver 版本支持
获取响应体
类似于请求体,ResponseDetails
事件触发时响应体不能直接获得。使用 Network.getResponseBody
命令, 同样需要 requestId
来定位对应的响应请求。
- 原理:浏览器接收到服务器响应后,你主动用这个命令获取返回的 body 信息. 同样返回base64编码的数据.
- 示例(Java)
import org.openqa.selenium.WebDriver; import org.openqa.selenium.bidi.Network; import org.openqa.selenium.bidi.network.BeforeRequestSent; import org.openqa.selenium.bidi.network.ResponseDetails; public class BidiNetworkMonitor { public static void main(String[] args) { // 使用你选择的浏览器驱动 WebDriver driver = WebDriverHelper.getChromeDriver(); Network network = ((HasDevTools) driver).getDevTools().getDomains().network(); network.onResponseDetailsReceived(response ->{ System.out.println("Response URL:" + response.getResponse().getUrl()); network.getResponseBody(response.getResponse().getRequestId()).thenAccept(body -> { if(body.isPresent()){ System.out.println("Response Body:" + body.get().text); } }); }); //加载测试页面或进行相关操作 driver.get("https://postman-echo.com/post"); // 防止进程退出 try{Thread.sleep(5000);} catch (InterruptedException e){ e.printStackTrace(); } driver.quit(); } }
- 步骤:
- 初始化 WebDriver 实例。
- 获取
Network
监听器。 - 为
onResponseDetailsReceived
设置回调函数。 - 通过
response.getResponse().getRequestId()
得到requestId - 使用
network.getResponseBody()
来请求响应体信息。 - 检查响应,如果 body.isPresent() 返回 true, 就处理数据
- 注意事项:
- 可能需要对返回的数据做 base64 解码,获取到真实的body
- 有些请求可能不会返回 body,如 204 Not Content, 必须处理 Optional.empty 的情况.
- 如果页面数据是通过 websocket 或者其他方法动态更新的, 你应该使用
network.fetchResponse
方法,而不是简单的Network.getResponseBody
. - 如果资源来自本地缓存, WebDriver Bidi将不会监听到。你需要禁用缓存策略.
额外的建议
- 异步处理 :
getRequestBody
和getResponseBody
是异步操作,需要用thenAccept
来正确处理. 使用 promise 和 async/await 可以使异步代码更加简洁. - 错误处理: 务必检查是否发生错误, 特别是
Network.getResponseBody
如果失败时会返回一个错误,使用CompletableFuture.exceptionally
进行错误捕获 - 安全性: 处理响应体数据时注意潜在的安全性风险,比如数据清洗和过滤,确保用户的数据隐私安全。
- 资源释放: 不再使用WebDriver 时确保关闭WebDriver,释放浏览器进程资源。
- 测试覆盖 : 进行全面的测试来验证请求体和响应体的正确获取。 使用真实的场景,确保处理各种不同情况.
总之, WebDriver BiDi提供了灵活的 API , 可以用来监测和处理网络活动,结合请求id, 获取body体数据也相对容易,只要你注意其中的一些细节.