<!-- Source: https://deepseek-browser-use.io.nexus/28 -->

# 请求响应关联与线程约束

同一个 URL 可以连续或并发请求多次。`get_requests` 给出的每个 requestId 必须对应那次请求的状态和正文，`get_response_body` 与 `wait_for_response` 也必须沿用这个 ID。只比 URL 或选择最近一条未完成请求，无法证明响应归属。

## 精确关联与有序采集

服务按请求对象关联响应，为同一 URL 的连续请求和并发请求分别保留 requestId。`get_requests`、`get_response_body` 与 `wait_for_response` 使用统一的登记逻辑，方便从请求记录追踪到响应状态和正文。

正文在下载完成事件中，由当前 Playwright 调用线程读取并缓存。采集与页面操作遵循相同的线程模型，便于保持浏览器事件顺序，并在后续命令中直接读取已保存的正文。

[Playwright Java 的线程说明](https://playwright.dev/java/docs/multithreading)要求同一 Playwright 实例及其派生对象在同一线程调用，或者保证任一时刻只有一个线程调用。服务按这一调用约定组织网络记录与正文采集。

## 当前记录流程

| 时机 | 操作 |
| --- | --- |
| request | 生成 requestId，保存请求元数据，登记请求对象，在途计数加一 |
| response | 按请求对象找到原记录，回填 status 和 respondedAt，在途计数减一，登记响应 |
| requestfinished | 下载完成，在当前 Playwright 调用线程读取并缓存 xhr/fetch 正文 |
| requestfailed | 若请求仍在待响应索引中，记录 failure 和 finishedAt，并释放在途计数 |

这里的在途计数表示尚未收到响应头或失败事件的请求数，不表示正文下载完成数。不要用它判断缓存是否已经写好。

正文缓存由下载完成事件触发，读取正文为同步调用，计入当前命令的执行时间。缓存只覆盖 xhr/fetch；流式响应在下载结束前不会进入完成缓存，提前读取完整正文仍可能等待。

同一响应重复进入记录逻辑时复用已有记录。`wait_for_response` 的等待分支也走同一个登记方法，沿用关联请求的 ID。

## 回执与异常分支

| 字段 | 含义 |
| --- | --- |
| requestId | 本次请求的标识，读取正文时原样传回 |
| correlationMissed: false、correlatedBy: identity | 已找到请求记录，响应沿用原 ID |
| correlationMissed: true、correlatedBy: none | 没找到请求记录；新记录明确标记缺失关联，不冒充相同 URL 的另一次请求 |
| bodyFromCache: true、bodyCapturedAt | 正文来自已保存的缓存及其保存时间 |
| bodyCapturePending: true | 可缓存类型尚未完成缓存，不等于没有收到响应头 |
| truncated、bodyCachedChars | 正文被返回长度限制或缓存上限截断；缓存上限截断时给出上限 |

只捕获到响应的情况可能发生在认领已有页签之后。新增记录中的 requestedAt 是补记时刻，不能当作真实发起时间。正常关联不生成第二个 requestId；缺失关联也不按 method、URL 或请求体进行猜测，因为这些字段完全相同的请求仍可能并发存在。

请求元数据最多保留 200 条，响应最多保留 100 条，正文每条最多缓存 100000 字符。缓存截断后，bodyLength 表示缓存中保留的字符数，不能据此推算完整响应长度。下载完成前就被容量限制淘汰的响应不会继续占用正文缓存。

## 回归验证

在浏览器服务模块目录执行：

```bash
mvn -o test -Dtest=BrowserResponseIntegrationTest -DfailIfNoTests=false
mvn -o test -Dtest=ResponseCorrelationTest -DfailIfNoTests=false
mvn -o test
```

集成测试使用临时浏览器 profile 和本地 HTTP 服务。验证连续两次请求只增加两条记录，并且不同请求体对应各自 requestId；另发出 12 个相同 URL 的并发请求，交错返回，逐条检查状态、正文、缓存和回调线程，导航后再检查缓存仍能读取。

单元测试直接断言正文读取发生在调用线程、重复缓存不重复读取、读取失败被记录，以及关联缺失不会占用另一个相同 URL 请求的 ID。等待响应超时会抛出包含请求总数和未响应数量的断言错误；不提高超时、不重发整个测试动作、不忽略失败用例。

参见[网络记录与请求拦截](<https://deepseek-browser-use.io.nexus/24>)、[整合 Playwright 的线程边界](https://tio-boot.com/zh/42_crawling/07.html)和[t-io 稳定性设计与资源管理](https://tio-boot.com/zh/34_tio/31-stability-resource-management.html)。IO 层管理连接与共享 Worker，浏览器层按 Playwright 的线程约定组织调用，两者共同完成请求处理。
