1
0

feat: 增强 HTTP checker 鲁棒性 — 严格配置校验、完整耗时、流式body、重定向与编码完善

启动期校验: 新增 validate.ts 对 HTTP config/expect/body rule/operator 全方位严格校验
执行语义: body 改为 Web Stream 流式超限中止,durationMs 覆盖完整执行
错误归属: status/header 失败不读 body,phase 分层 request/body,early duration skip body
重定向: 跟随前释放 body,POST/303 改 GET 清理 header,跨 origin 剥离敏感 header
编码: 支持 quoted charset,未知编码返回结构化解码错误
文档: README match→regex+durationMs,DEVELOPMENT 执行流程与错误归属
测试: +63 测试覆盖全部新增场景,325 pass 0 fail
规格: 同步 probe-config/probe-engine/expect-body-checkers 3 个 delta spec
This commit is contained in:
2026-05-13 08:00:05 +08:00
parent 2fd0f206be
commit bce0f8e7a8
14 changed files with 1543 additions and 104 deletions

View File

@@ -31,7 +31,7 @@
- **THEN** 系统 MUST 同时最多运行 3 个检查,其余检查等待并发槽位释放
### Requirement: HTTP 拨测执行
系统 SHALL 对 `type: http` 的目标执行 HTTP 请求,支持 GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS 方法,并携带 `http.headers``http.body`。系统 SHALL 支持 `http.ignoreSSL` 配置跳过 SSL 证书校验,支持 `http.maxRedirects` 配置控制重定向行为。
系统 SHALL 对 `type: http` 的目标执行 HTTP 请求,支持 GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS 方法,并携带 `http.headers``http.body`。系统 SHALL 支持 `http.ignoreSSL` 配置跳过 SSL 证书校验,支持 `http.maxRedirects` 配置控制重定向行为。HTTP response body 读取 SHALL 受 `http.maxBodyBytes` 流式限制,重定向跟随 SHALL 释放被跟随响应的 body。
#### Scenario: 执行 GET 请求
- **WHEN** 目标配置 method 为 GET
@@ -47,7 +47,15 @@
#### Scenario: HTTP body 读取上限
- **WHEN** HTTP response body 超过该 target 的 maxBodyBytes
- **THEN** 系统 MUST 停止读取并记录 `matched=false`结构化输出超限错误
- **THEN** 系统 MUST 停止继续读取 response body并记录 `matched=false``failure.kind="error"``failure.phase="body"`结构化输出超限错误
#### Scenario: HTTP body 大小等于上限
- **WHEN** HTTP response body 的字节数等于该 target 的 maxBodyBytes
- **THEN** 系统 SHALL 允许该 body 进入后续解码和 expect 校验
#### Scenario: HTTP body 上限为 0
- **WHEN** HTTP target 配置 maxBodyBytes 为 0 且响应体非空
- **THEN** 系统 SHALL 停止读取并记录 body 超限错误
#### Scenario: 忽略 SSL 证书校验
- **WHEN** 目标配置 `http.ignoreSSL: true` 且目标 URL 为 HTTPS
@@ -63,20 +71,32 @@
#### Scenario: 配置跟随重定向
- **WHEN** 目标配置 `http.maxRedirects: 5` 且服务端返回重定向
- **THEN** 系统 SHALL 跟随重定向,最多跟随 5 次
- **THEN** 系统 SHALL 跟随重定向,最多跟随 5 次,并在跟随前释放当前重定向响应的 body
#### Scenario: 超过最大重定向次数
- **WHEN** 目标配置 `http.maxRedirects: 1` 且服务端连续返回两次重定向
- **THEN** 系统 SHALL 只跟随第一次重定向,并返回第二次重定向响应的状态码和响应头
#### Scenario: POST 重定向改 GET
- **WHEN** POST 请求遇到 301/302 或任意方法请求遇到 303且系统决定按 GET 跟随重定向
- **THEN** 系统 SHALL 移除请求 body并清理 content-type、content-length 等 body 相关 headers 后发起后续 GET 请求
#### Scenario: 跨 origin 重定向敏感 header
- **WHEN** HTTP 请求跟随重定向到不同 origin
- **THEN** 系统 SHALL NOT 将 authorization、cookie 等敏感 headers 转发到新的 origin
#### Scenario: 响应体编码自动检测
- **WHEN** HTTP 响应的 `Content-Type` header 包含 `charset=gbk`
- **WHEN** HTTP 响应的 `Content-Type` header 包含 `charset=gbk``charset="gbk"`
- **THEN** 系统 SHALL 使用 GBK 编码解码响应体,而非硬编码 UTF-8
#### Scenario: 响应体编码回退 UTF-8
- **WHEN** HTTP 响应的 `Content-Type` header 未指定 charset
- **THEN** 系统 SHALL 使用 UTF-8 编码解码响应体
#### Scenario: 响应体编码不支持
- **WHEN** HTTP 响应的 `Content-Type` header 指定了当前运行时不支持的 charset
- **THEN** 系统 SHALL 记录 `matched=false``failure.kind="error"``failure.phase="body"` 的解码失败结果
### Requirement: 请求超时控制
系统 SHALL 对每次 checker 执行实施超时控制,超时时间使用目标配置的 timeout 值。
@@ -93,7 +113,7 @@
- **THEN** 系统 SHALL 正常记录执行结果并进入 expect 校验
### Requirement: expect 校验
系统 SHALL 在 checker 执行完成后根据目标类型的 expect 配置校验观测结果,校验结果和首个失败原因记入 check result。
系统 SHALL 在 checker 执行完成后根据目标类型的 expect 配置校验观测结果,校验结果和首个失败原因记入 check result。HTTP checker 的 `durationMs` SHALL 表示完整 checker 执行耗时,包括重定向、响应体读取、响应体解码和 expect 校验。
#### Scenario: HTTP 默认状态码
- **WHEN** HTTP target 未配置 `expect.status`
@@ -119,6 +139,26 @@
- **WHEN** HTTP target 配置了有序 `expect.body` 规则数组
- **THEN** 系统 SHALL 按数组顺序执行 body 规则,任一失败立即记录 failure 并停止后续规则
#### Scenario: 校验 HTTP 完整耗时阈值
- **WHEN** 目标配置了 `expect.maxDurationMs`,且 HTTP checker 完整执行含重定向、body 读取、解码和 expect后的 durationMs 超过阈值
- **THEN** 系统 SHALL 判定 duration 不匹配,记录完整 durationMs 和 duration failure
#### Scenario: HTTP body 前耗时已超阈值
- **WHEN** HTTP target 配置了 body 校验和 `expect.maxDurationMs`,且进入 body 读取前的已耗时已超过阈值
- **THEN** 系统 SHALL 直接返回 duration failure且 MUST NOT 读取 response body
#### Scenario: HTTP body 失败优先于后续 duration 检查
- **WHEN** HTTP target 配置了 body 校验和 `expect.maxDurationMs`body 阶段存在失败,且完整执行后 duration 也超过阈值
- **THEN** 系统 SHALL 返回 body 阶段的失败首个失败为准durationMs SHALL 记录完整耗时
#### Scenario: HTTP 慢响应体计入耗时
- **WHEN** HTTP target 配置了 body 校验和 `expect.maxDurationMs`,且响应头很快返回但响应体读取导致完整执行耗时超过阈值
- **THEN** 系统 SHALL 判定 duration 不匹配并记录完整 durationMs
#### Scenario: 多条 expect 规则
- **WHEN** 目标同时配置状态、duration、元数据和内容规则
- **THEN** 系统 SHALL 所有规则全部通过时 matched 为 true任一不通过则为 false 并记录首个失败原因
#### Scenario: command 默认 exitCode
- **WHEN** command target 未配置 `expect.exitCode`
- **THEN** 系统 SHALL 按默认 `exitCode: [0]` 校验命令退出码
@@ -127,21 +167,21 @@
- **WHEN** command target 配置了有序 `expect.stdout` 规则数组
- **THEN** 系统 SHALL 按数组顺序执行 stdout 规则,任一失败立即记录 failure 并停止后续规则
#### Scenario: 校验耗时阈值
- **WHEN** 目标配置了 `expect.maxDurationMs`
- **THEN** 系统 SHALL 检查实际 durationMs 是否超过阈值,将匹配结果记录到 matched 字段
#### Scenario: 多条 expect 规则
- **WHEN** 目标同时配置状态、duration、元数据和内容规则
- **THEN** 系统 SHALL 所有规则全部通过时 matched 为 true任一不通过则为 false 并记录首个失败原因
### Requirement: Body 校验按需解析
系统 SHALL 仅在 HTTP target 配置了 body 校验且 status、duration、headers 阶段均通过时才读取并解析响应体,避免不必要的读取和解析开销
系统 SHALL 仅在 HTTP target 配置了 body 校验且 status、headers 阶段均通过,并且进入 body 前未确定 duration 已失败时才读取并解析响应体避免不必要的读取和解析开销。HTTP target 未配置 body 校验时,系统 SHALL NOT 读取 response body
#### Scenario: status 失败时不读取 body
- **WHEN** HTTP target 的 status 阶段不匹配
- **THEN** 系统 SHALL 立即返回 matched=false且 MUST NOT 读取 response body
#### Scenario: headers 失败时不读取 body
- **WHEN** HTTP target 的 status 阶段匹配但 headers 阶段不匹配
- **THEN** 系统 SHALL 立即返回 matched=false且 MUST NOT 读取 response body
#### Scenario: 进入 body 前 duration 已失败时不读取 body
- **WHEN** HTTP target 已配置 `expect.maxDurationMs`,且进入 body 读取前的已耗时已经超过阈值
- **THEN** 系统 SHALL 返回 duration failure且 MUST NOT 读取 response body
#### Scenario: 仅配置 contains 时不解析 JSON
- **WHEN** HTTP target 仅配置 body contains 规则而未配置 json/css/xpath 规则
- **THEN** 系统 SHALL 不执行 JSON.parse 或 HTML/XML 解析
@@ -150,6 +190,21 @@
- **WHEN** HTTP target 配置了 body json 规则但响应体不是合法 JSON
- **THEN** 系统 SHALL 判定 matched 为 false并记录 json 规则对应的 failure.path
### Requirement: HTTP 运行期错误归属
HTTP checker SHALL 将运行期失败归属到实际失败阶段。请求、网络、TLS 和 timeout 错误 SHALL 记录为 request 阶段错误body 超限、响应体解码失败、响应内容解析失败 SHALL 记录为 body 阶段错误expect 不匹配 SHALL 记录为对应 mismatch 阶段。
#### Scenario: 请求错误归属 request
- **WHEN** HTTP 请求因为网络、TLS 或 timeout 失败
- **THEN** 系统 SHALL 记录 `matched=false``failure.kind="error"``failure.phase="request"`
#### Scenario: body 超限归属 body
- **WHEN** HTTP response body 超过 maxBodyBytes
- **THEN** 系统 SHALL 记录 `failure.kind="error"``failure.phase="body"``failure.path="body"`
#### Scenario: body 解析错误归属 body
- **WHEN** HTTP response body 已读取但解码、JSON 解析、CSS 解析或 XPath 解析失败
- **THEN** 系统 SHALL 记录 `failure.phase="body"`,且 SHALL NOT 将该失败记录为 request 错误
### Requirement: 拨测结果记录
系统 SHALL 在每次 checker 完成后,将结果写入 SQLite 数据存储,包含 target_id、timestamp、matched、duration_ms、status_detail、failure 字段。