feat(debug): 增加 HTTP 请求响应日志

This commit is contained in:
Zhou Weidong committed 2026-10-22 12:15:51 +08:00
1 parent dc4b60270d
commit 7a588898fa
6 files changed
+534

No files matched your search

@@ -0,0 +1,24 @@
# Android Studio 调试 HTTP 日志
## 目标
- 仅在调试构建中输出 Dio 请求、响应与异常日志。
- Android Studio Run 控制台通过 `debugPrint` 展示,logcat 标签保持 `flutter`。
- Authorization 脱敏,X-Device-Id 保留,二进制响应只显示字节数。
- 单条请求体或响应体最多 3000 字符。
## 实现步骤
1. 新增 `NetworkLogInterceptor`,支持注入日志回调并保留请求耗时。
2. 在 Envelope 解包前暂存原始 bytes;日志拦截器追加到拦截链末尾后读取暂存值。
3. 在 `ApiClient` 注册调试拦截器,`kDebugMode` 与常量开关同时满足时才输出。
4. 以 fake adapter 补单测,覆盖行格式、脱敏、UTF-8、截断、非 JSON 与二进制。
5. 运行 `dart analyze lib test` 和 `flutter test`,更新 PROGRESS 留痕。
## 风险与约束
- `ResponseType.bytes` 不能直接 `toString`,响应体统一 `utf8.decode`。
- Dio 响应拦截器按 FIFO 执行;链尾日志通过 Envelope 暂存的原始 bytes 读取,
避免拿到已解包后的 `data`。
- release/profile 通过 `kDebugMode` 短路,不输出任何 HTTP 日志。
- 不新增依赖,不提交现有 `pubspec.lock` 改动,不启停服务、不操作真机。
+79
View File
@@ -531,3 +531,82 @@ $ flutter test --no-pub
解读:VTT 时间/xywh/多 sprite、越界最近 cue、LRU2、403 重试、10 分钟 TTL、
回退链、sprite 零本地取帧、无 URL 本地回退和最终封面兜底均通过;全量静态分析
零告警,617 项测试全过。`pubspec.lock` 已还原,未启停服务,未操作真机。
## 2026-10-22 Android Studio 调试 HTTP 日志
- 分支:`feature/debug-http-logging`
- 基线:`develop` / `origin/develop` = `dc4b602`
- 计划:`docs/plans/2026-10-22-debug-http-logging.md`
```text
$ git status --short --branch
## develop...origin/develop
M pubspec.lock
$ git rev-parse HEAD
dc4b60270dd38d594510b45bd7a3d50b7dcd2602
```
解读:基于最新 develop 创建功能分支;开工时 `pubspec.lock` 已有未提交改动,
本次未修改、未暂存该文件。
### 实现结果
- 新增 `NetworkLogInterceptor`,默认 `debugPrint`,可注入
`void Function(String)` 作为单测日志收集器。
- `enabled` 常量与 `kDebugMode` 同时为真才输出,release/profile 零 HTTP 日志。
- 请求行包含完整 URL 与 query,同时输出耗时起点、脱敏请求头和格式化请求体。
- Authorization 仅保留前 8 字符后加 `...`;X-Device-Id 原样输出;
其余请求头值统一 `***`。
- ResponseType.bytes 响应统一 `utf8.decode(..., allowMalformed: true)`,
JSON 自动缩进;图片/音视频/字体/PDF/ZIP 等只输出 MIME 与字节数。
- 请求体和响应体超过 3000 字符时截断并追加 `…(truncated)`。
- 拦截链为 `AuthHeaderInterceptor → EnvelopeInterceptor → NetworkLogInterceptor`。
Envelope 在解包前暂存原始 bytes,末尾日志读取暂存值,因此仍能打印 Envelope
处理前的原始响应。
- 异常路径输出 `[HTTP] ✗ DioException类型 耗时ms URL message`,并继续
`handler.next(err)`,不吞异常。
代表性原始日志:
```text
[HTTP] → POST http://logging.test/app/logging?keyword=%E4%B8%AD%E6%96%87
[HTTP] → 耗时起点:2026-10-22T12:12:25.377357
[HTTP] → headers:{"Accept":"***","Authorization":"Bearer e...","X-Device-Id":"device-raw-001"}
[HTTP] → body:{
"filter": "中文"
}
[HTTP] ← 200 12ms POST http://logging.test/app/logging?keyword=%E4%B8%AD%E6%96%87
[HTTP] ← body:{
"code": 0,
"message": "ok",
"data": {
"title": "中文标题"
}
}
```
### 门禁
```text
$ flutter test --no-pub test/core/data/remote/network_log_interceptor_test.dart
00:00 +0: should_log_request_and_response_lines_with_elapsed_when_requested
00:00 +1: should_truncate_long_body_when_log_exceeds_limit
00:00 +2: should_log_plain_text_without_throwing_when_response_is_not_json
00:00 +3: should_log_byte_count_only_when_response_is_image
00:00 +4: should_log_dio_exception_type_and_message_when_request_fails
00:00 +5: All tests passed!
$ dart analyze lib test
Analyzing lib, test...
No issues found!
$ flutter test --no-pub
00:58 +622: All tests passed!
```
解读:请求/响应行与耗时、Authorization 脱敏、X-Device-Id 原样、bytes 中文
UTF-8 解码、3000 字符截断、非 JSON、二进制字节数、DioException 类型与 message
均通过;全量静态分析零告警,622 项测试全过。
未新增依赖、未启停服务、未操作真机;`pubspec.lock` 既有改动未提交。