@evalexp/pi-http1.0.2
A minimal HTTP/1.1 request tool for Pi with raw request and response snapshots
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
pi-http
一个简洁的 Pi HTTP/1.1 请求工具。每次调用发送一次请求,直接返回 HTTP 响应。工具提示默认将直接 HTTP 请求、接口调用和原生请求/响应检查交给 http,尤其适用于需要控制方法、查询参数、请求头、正文、TLS 和 snapshot 的操作。
使用 Node 标准库 node:http / node:https;运行时仅依赖 Pi 提供的 typebox,不需要 curl、OpenSSL 或其他外部命令。支持 Node.js 22.19 或更新版本,也已在 Bun 1.4.4 下验证。
安装
pi install npm:@evalexp/pi-http
本地开发时可以从项目目录加载:
npm ci
pi -e ./src/index.ts
请求参数
工具名为 http。
| 参数 | 类型 | 必填 | 含义 |
|---|---|---|---|
method |
string | 是 | HTTP 方法,例如 GET、POST。发送时转为大写。 |
url |
string | 是 | 完整的 http:// 或 https:// URL,包含路径和查询参数。 |
headers |
object | 否 | 头字段到字符串的映射;字符串数组表示同名头字段的多个值。 |
body |
string / object | 否 | 原始 UTF-8 字符串、{ "file": "路径" } 原始文件正文,或 { "multipart": [...] } 表单。GET 和 HEAD 禁止设置。 |
verifyTls |
boolean | 否 | 是否严格校验证书及主机名,默认 true。 |
snapshot |
string | 否 | 请求与响应的文件路径前缀 / ID。绝对路径直接使用;相对路径以 Pi 当前会话工作目录为基准,可指向工作目录之外。 |
{
"method": "POST",
"url": "https://localhost:8443/api/items?draft=true",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer example-token"
},
"body": "{\"name\":\"example\"}",
"verifyTls": false,
"snapshot": ".auto-audit/V0001/verify-1"
}
JSON、表单等字符串正文由调用方自行序列化并设置 Content-Type。字符串原样按 UTF-8 发送,也可以配合调用方指定的 Content-Type: multipart/form-data; boundary=... 发送手写的 multipart 字符串。
multipart 也可以由工具组装,支持普通字符串参数、文件、空字符串和重复字段名,并保留数组顺序:
{
"method": "POST",
"url": "https://example.com/upload",
"body": {
"multipart": [
{ "name": "title", "value": "普通字符串参数" },
{ "name": "tag", "value": "one" },
{ "name": "tag", "value": "two" },
{
"name": "attachment",
"file": "./sample.bin",
"filename": "upload.bin",
"contentType": "application/octet-stream"
}
]
},
"snapshot": ".auto-audit/V0001/upload"
}
工具读取文件原始字节,使用 Node/Bun 原生 FormData 编码并生成 boundary,自动设置带 boundary 的 Content-Type。此时省略请求头 Content-Type,或只写不带 boundary 的 multipart/form-data;其它值会被拒绝,避免头部与实际编码不一致。文件的 filename 默认取本地文件名,contentType 默认 application/octet-stream。原生编码器可能为文本文件类型补充 UTF-8 charset。
如果你们自行组装了含不可见字符的 multipart 或其它二进制正文,可直接传入完整正文文件:
{
"method": "POST",
"url": "https://example.com/upload",
"headers": {
"Content-Type": "multipart/form-data; boundary=my-boundary"
},
"body": { "file": "./request-body.bin" }
}
body.file 和 multipart 文件路径都相对 Pi 当前会话工作目录解析。这种完整文件正文不做任何编码或拼接,按原始字节发送;字符串正文也不会被 multipart 逻辑重新处理。
工具补充必要的 Host、Connection: close 和 Content-Length,正文长度按最终发送的字节计算。手动提供的 Content-Length 必须匹配正文,不接受手动指定 Transfer-Encoding。URL 中的凭据应改用 Authorization 请求头,URL 不接受 fragment。
返回响应
可显示的响应以 HTTP 报文文本返回,正文保留原有格式:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 14
X-Pi-Http-Started-At: 1700000000000
X-Pi-Http-Timespan: 123.45 ms
{ "ok": true }
Node IncomingMessage 会自动移除 chunked 分块编码,但不会解压 Content-Encoding。工具继续解码标准 gzip、deflate 和 br(Brotli)内容编码,支持叠加编码;随后移除已解码的编码头,按解码后的正文重算 Content-Length。不解析 JSON、不重新排版、不转换字符集,也不转换 Base64。未知编码保留原样;解码失败会明确返回错误并保留未能解码的正文。
响应中间状态(例如 100 Continue、103 Early Hints)会保留;其它头字段保留大小写、顺序和多个值。收到的 trailers 以附加头字段的方式放入最终响应的头部,原有 Trailer 声明随 chunked 编码移除。HEAD、204、304 响应没有正文,不进行内容解压。
X-Pi-Http-Started-At 是工具本地记录的请求开始时间,以 Unix epoch 毫秒整数表示;结构化详情中的 details.startedAtMs 与该头的数值一致。它与 durationMs 在 HTTP 请求开始时一起采样,不包含请求正文文件读取和 snapshot 文件预留时间。
X-Pi-Http-Timespan 是工具本地添加的响应头,单位为毫秒,保留两位小数。它测量从本次 HTTP 请求开始到响应接收完成的时间,包括 DNS、连接、TLS、请求发送和响应接收,不包括正文文件读取、解压和 snapshot 写盘。返回文本和响应 snapshot 中都会包含这两个时间头;结构化详情同时提供 startedAtMs 和 durationMs,通过 startedAtMs + durationMs 可计算响应接收完成的 Unix 毫秒时刻。这两个头名由工具保留,服务端同名字段会被本次测量值替换。
二进制、非 UTF-8 或含不可见控制字符的响应返回文件读取路径。超过 48 KiB 或 1500 行的文本只显示开头,同时提供完整响应的文件路径:
- 指定
snapshot:使用指定的响应文件,不额外创建临时副本。 - 未指定
snapshot:在系统临时目录创建pi-http-*/response.http,按字节保存完整响应。
临时文件保存失败会单独记录为 details.outputError,保留已经收到的 HTTP 状态、完整性和耗时;写入失败的临时文件会清理,失败路径不会被当作可读取的响应文件返回。
HTTP 3xx、4xx、5xx 都是正常响应。工具不跟随重定向、不重试、不持久化 Cookie。每次请求独立,HTTP 收发与响应解压共用 30 秒 deadline,两个阶段都支持 Pi 取消操作;不提供 HTTP/2、CONNECT 隧道或协议升级。
Snapshot
snapshot 是文件前缀,不是目录。绝对路径直接使用,相对路径从当前会话工作目录解析;../ 也按正常路径规则解析,不限制保存在工作目录内。上面的示例产生两个文件:
.auto-audit/V0001/verify-1.request.http
.auto-audit/V0001/verify-1.response.http
文件内容是 HTTP 起始行、头字段、空行和正文,使用 CRLF 分隔,正文按字节保存。请求文件保存本次请求报文;响应文件与返回响应采用相同的 HTTP 编码解码结果,包含本地耗时头,不做正文重排或额外编码。父目录自动创建,已有同名文件不会被覆盖;工具会在发送请求之前预留两个文件。
发生连接失败、超时或取消时,仍保存请求和已经收到的响应。如果尚未收到响应,响应文件为空。工具结果中的 details.complete、details.requestWritten 和 details.error 说明响应完整性、请求是否写入完成及失败原因;写入完成不代表服务器已经接收。Snapshot 写入失败也会明确返回错误,目标路径不会被标记为已保存的完整响应文件。
开发
src/
index.ts Pi 工具入口
schema.ts 六个请求参数
body.ts 字符串、原始文件正文与原生 multipart 编码
request.ts HTTP/HTTPS 请求及报文封装
response.ts 标准响应解压与协议头同步
snapshot.ts 两个 snapshot 文件的保存
output.ts 原生文本输出及文件路径处理
tests/
*.test.ts HTTP、HTTPS、解压、取消、文件输出和工具集成验证
fixtures/ 仅用于本地测试的自签名证书与测试私钥
npm ci
npm run typecheck
npm test
npm run test:bun
npm pack --dry-run
开发和 CI 使用提交的 package-lock.json 与 npm ci 安装同一棵依赖树。需要调整依赖时再使用 npm install,并将更新后的 lockfile 一同提交,避免每次测试重新解析浮动依赖和可选 peer 依赖。
实现与测试使用跨平台 API。测试证书仅供本地验证使用,不用于生产。GitHub Actions 配置了 Windows、Linux 和 macOS 上的 Node 22.19 / 24 与 Bun 1.4.4 测试,并显式检查测试所用的 runtime。