返回

WebDriver BiDi: 如何获取网络请求和响应体?

java

WebDriver BiDi:获取请求和响应体

使用WebDriver BiDi监听网络事件时,获取请求和响应体是一项常见的需求,这对于调试和自动化测试至关重要。 本文探讨如何有效地捕获 BeforeRequestSentResponseDetails 事件中的请求体和响应体。

理解事件数据结构

BeforeRequestSentResponseDetails 事件提供关于网络活动的关键信息, 但并非直接包含请求体和响应体的完整数据。BeforeRequestSent 事件主要关注请求的初始化,包括 URL,方法,headers, 并没有请求体的原始字节序列或JSON形式。同样,ResponseDetails 事件提供了响应头和状态码等,也没有包含响应体的完整内容。

问题的核心在于,BeforeRequestSentResponseDetails 事件设计为传递轻量级信息,如果包含完整的 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();
    
          }
    
     }
    
    
  • 步骤:
    1. 初始化 WebDriver 实例。
    2. 获取 Network 监听器。
    3. onBeforeRequestSent 设置回调函数,每次收到请求都执行.
    4. 通过 request.getRequest().getRequestId() 获取到当前请求的id
    5. 调用 network.getRequestBody() 获取 body 信息
    6. 对返回结果进行判断处理, 如果 body.isPresent() 说明请求有body 数据
  • 注意事项:
    • 需要确保使用的 WebDriver 版本支持 getRequestBody 命令
    • 请求体可能是多种格式 (text, json, xml etc),需要在代码中做处理
    • Network.getRequestBody() 可能返回空 Optional 对象,此时,你需要额外的检查逻辑

获取响应体

类似于请求体,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();
             }
      }
    
    
    
    • 步骤:
    1. 初始化 WebDriver 实例。
    2. 获取 Network 监听器。
    3. onResponseDetailsReceived 设置回调函数。
    4. 通过 response.getResponse().getRequestId() 得到requestId
    5. 使用 network.getResponseBody() 来请求响应体信息。
    6. 检查响应,如果 body.isPresent() 返回 true, 就处理数据
  • 注意事项:
  • 可能需要对返回的数据做 base64 解码,获取到真实的body
  • 有些请求可能不会返回 body,如 204 Not Content, 必须处理 Optional.empty 的情况.
  • 如果页面数据是通过 websocket 或者其他方法动态更新的, 你应该使用 network.fetchResponse 方法,而不是简单的Network.getResponseBody.
  • 如果资源来自本地缓存, WebDriver Bidi将不会监听到。你需要禁用缓存策略.

额外的建议

  • 异步处理 : getRequestBodygetResponseBody 是异步操作,需要用 thenAccept 来正确处理. 使用 promise 和 async/await 可以使异步代码更加简洁.
  • 错误处理: 务必检查是否发生错误, 特别是 Network.getResponseBody 如果失败时会返回一个错误,使用CompletableFuture.exceptionally 进行错误捕获
  • 安全性: 处理响应体数据时注意潜在的安全性风险,比如数据清洗和过滤,确保用户的数据隐私安全。
  • 资源释放: 不再使用WebDriver 时确保关闭WebDriver,释放浏览器进程资源。
  • 测试覆盖 : 进行全面的测试来验证请求体和响应体的正确获取。 使用真实的场景,确保处理各种不同情况.

总之, WebDriver BiDi提供了灵活的 API , 可以用来监测和处理网络活动,结合请求id, 获取body体数据也相对容易,只要你注意其中的一些细节.