- 新增 TraceRecorder 和 TraceSummary,汇总 DNS、连接、TLS、写请求、首包等关键事件 - 为请求执行链接入结构化 trace hooks,补充标准路径与动态路径的 TLS 元信息 - 增加 Request.TraceSummary() 和 Response.TraceSummary(),提供请求级与响应级摘要快照 - 修复共享 TraceRecorder 在 Client 默认选项、Clone 和请求复用场景下的状态串扰问题 - 修复 Response.TraceSummary() 回读 Request 最近状态导致的非快照语义 - 收口自定义 DialFunc 下的 TLS trace 元数据,避免伪造连接地址 - 补充 trace 相关回归测试,覆盖 HTTPS、DNS/Connect、连接复用、共享 recorder、响应快照和自定义拨号场景 - 更新 README,补充 trace、Host 与 TLSServerName 的行为说明
123 lines
4.8 KiB
Markdown
123 lines
4.8 KiB
Markdown
# starnet
|
||
|
||
`starnet` 是一个面向 Go 的网络工具库,提供 HTTP 请求控制、TLS 嗅探和 ICMP Ping 能力。
|
||
|
||
## 功能概览
|
||
|
||
- 基于 `context` 的请求级超时控制,不修改共享 `http.Client` 的全局超时
|
||
- 请求级网络控制:代理、自定义 IP / DNS、拨号超时、TLS 配置
|
||
- 支持请求级 `Host` 覆盖、显式 `TLSServerName/SNI` 控制,以及结构化 trace 回调 / 摘要
|
||
- 内置重试机制,支持重试次数、退避、抖动、状态码白名单和自定义错误判定
|
||
- 响应体大小限制,避免一次性读取过大内容
|
||
- 错误分类辅助:`ClassifyError`、`IsTimeout`、`IsDNS`、`IsTLS`、`IsProxy`、`IsCanceled`
|
||
- TLS 嗅探监听 / 拨号工具,适用于 TLS 与明文混合场景
|
||
- ICMP Ping,支持 IPv4 / IPv6 目标和选项化探测
|
||
|
||
## 主要能力
|
||
|
||
### HTTP 客户端与请求构建
|
||
|
||
- 同时提供 `WithXxx` 选项和 `SetXxx` 链式调用两套接口
|
||
- 支持 `Get`、`Post`、`Put`、`Delete`、`Head`、`Patch`、`Options`、`Trace`、`Connect`
|
||
- 支持 JSON、表单、`multipart/form-data`、流式请求体等常见请求体形态
|
||
- 支持显式 `Host` 覆盖与 `TLSServerName` 设置,便于直连 IP、虚拟主机和证书校验场景分离控制
|
||
- Header、Cookie、Query 等输入在关键路径上做防御性拷贝,降低外部可变状态污染风险
|
||
- `Request.Clone()` 可用于并发场景或同一基础请求的变体构造
|
||
|
||
### Trace 与诊断
|
||
|
||
- 支持 `TraceHooks`,可接收 DNS、建连、TLS 握手、写请求、首包等结构化事件
|
||
- 支持 `TraceRecorder` / `TraceSummary`,用于汇总一次请求的关键网络过程和 TLS 摘要
|
||
- `Request.TraceSummary()` 返回该请求最近一次执行的摘要快照,`Response.TraceSummary()` 返回当前响应对应的摘要快照
|
||
- 若多个请求共享同一个 `TraceRecorder`,其 `Summary()` 表示最近一次完成请求的摘要
|
||
|
||
### 超时与重试
|
||
|
||
- 请求超时通过 `context` 截止时间控制,不污染共享客户端配置
|
||
- 重试支持:
|
||
- 最大尝试次数
|
||
- 基础退避、最大退避和退避因子
|
||
- 抖动比例
|
||
- 可重试状态码集合
|
||
- 仅幂等方法重试
|
||
- 自定义错误判定函数
|
||
- 重试成功后返回的 `Response` 仍保持对原始 `Request` 的引用
|
||
|
||
### 响应处理
|
||
|
||
- 提供 `Bytes`、`String`、`JSON`、`Reader` 等响应体读取接口
|
||
- 支持自动预取响应体
|
||
- 支持按字节数限制响应体读取上限
|
||
|
||
### Ping 模块
|
||
|
||
- 提供 `Ping`、`PingWithContext`、`Pingable` 以及兼容函数 `IsIpPingable`
|
||
- `PingOptions` 支持次数、超时、间隔、截止时间、地址族偏好、源地址、负载长度等参数
|
||
- 对权限不足、协议不支持、超时、解析失败等情况提供明确错误语义
|
||
|
||
## 安装
|
||
|
||
```bash
|
||
go get b612.me/starnet
|
||
```
|
||
|
||
## 快速示例
|
||
|
||
```go
|
||
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"net/http"
|
||
"time"
|
||
|
||
"b612.me/starnet"
|
||
)
|
||
|
||
func main() {
|
||
resp, err := starnet.Get(
|
||
"https://example.com",
|
||
starnet.WithTimeout(2*time.Second),
|
||
starnet.WithRetry(2,
|
||
starnet.WithRetryBackoff(100*time.Millisecond, 1*time.Second, 2),
|
||
starnet.WithRetryJitter(0.1),
|
||
),
|
||
starnet.WithMaxRespBodyBytes(1<<20),
|
||
)
|
||
if err != nil {
|
||
fmt.Println("request failed:", starnet.ClassifyError(err), err)
|
||
return
|
||
}
|
||
defer resp.Close()
|
||
|
||
fmt.Println("status:", resp.StatusCode)
|
||
_, _ = resp.Body().Bytes()
|
||
|
||
ok, pingErr := starnet.Pingable("example.com", &starnet.PingOptions{
|
||
Count: 2,
|
||
Timeout: 2 * time.Second,
|
||
})
|
||
fmt.Println("pingable:", ok, pingErr == nil)
|
||
|
||
_ = http.MethodGet
|
||
}
|
||
```
|
||
|
||
## 行为说明
|
||
|
||
- `NewClient`、`NewRequest` 以及请求构造相关接口在遇到非法选项时会直接返回错误,例如格式不合法的代理地址。
|
||
- `NewClientNoErr` 是便利构造函数;如果选项校验失败,仍可能返回一个占位 `Client`,需要严格校验配置时应优先使用 `NewClient`。
|
||
- `SetHost` / `WithHost` 只覆盖 HTTP 请求的 `Host`;如需单独控制 TLS SNI 或证书校验名,应配合 `SetTLSServerName` / `WithTLSServerName` 使用。
|
||
- 重试默认仅对幂等方法生效。即使显式关闭“仅幂等方法重试”,通过 `SetBodyReader` 或 `WithBodyReader` 构造的请求在非幂等方法上仍不会自动重试。
|
||
- 当同时使用 `proxy + custom IP/DNS` 且解析出多个目标地址时,自动目标回退仅对幂等请求生效,以避免重复写入。
|
||
- 绑定到请求上的 `TraceRecorder` 用于发布已完成请求的摘要;请求执行中的中间状态不保证通过共享 recorder 实时可见。
|
||
|
||
## 稳定性说明
|
||
|
||
- 原始 ICMP Ping 在部分系统上需要额外权限。
|
||
- 依赖外部网络环境的集成测试结果可能受运行环境影响。
|
||
|
||
## 许可证
|
||
|
||
本项目采用 Apache License 2.0,详见 [LICENSE](./LICENSE)。
|