starnet/README.md
starainrt 732e81316c
fix(starnet): 重构请求执行链路并补齐代理/重试/trace边界
- 分离 Request 的配置态与执行态,修复二次 Do、raw 模式网络配置失效和 body 来源互斥问题
  - 新增 starnet trace 抽象,补齐 DNS/连接/TLS/重试事件,并优化动态 transport 缓存与代理解析路径
  - 收紧非法代理为 fail-fast,多目标目标回退仅限幂等请求,修复 Host/TLS/SNI 等语义边界
  - 补充防御性拷贝、专项回归测试、本地代理/TLS 用例与 README 行为说明
2026-04-19 15:39:51 +08:00

112 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# starnet
`starnet` 是一个面向 Go 的网络工具库,提供 HTTP 请求控制、TLS 嗅探和 ICMP Ping 能力。
## 功能概览
- 基于 `context` 的请求级超时控制,不修改共享 `http.Client` 的全局超时
- 请求级网络控制:代理、自定义 IP / DNS、拨号超时、TLS 配置
- 内置重试机制,支持重试次数、退避、抖动、状态码白名单和自定义错误判定
- 响应体大小限制,避免一次性读取过大内容
- 错误分类辅助:`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`、流式请求体等常见请求体形态
- Header、Cookie、Query 等输入在关键路径上做防御性拷贝,降低外部可变状态污染风险
- `Request.Clone()` 可用于并发场景或同一基础请求的变体构造
### 超时与重试
- 请求超时通过 `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`
- 重试默认仅对幂等方法生效。即使显式关闭“仅幂等方法重试”,通过 `SetBodyReader``WithBodyReader` 构造的请求在非幂等方法上仍不会自动重试。
- 当同时使用 `proxy + custom IP/DNS` 且解析出多个目标地址时,自动目标回退仅对幂等请求生效,以避免重复写入。
## 稳定性说明
- 原始 ICMP Ping 在部分系统上需要额外权限。
- 依赖外部网络环境的集成测试结果可能受运行环境影响。
## 许可证
本项目采用 Apache License 2.0,详见 [LICENSE](./LICENSE)。