starnet

package module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 24, 2026 License: Apache-2.0 Imports: 22 Imported by: 2

README

starnet

starnet 是一个面向 Go 的网络工具库,提供 HTTP 请求控制、TLS 嗅探和 ICMP Ping 能力。

功能概览

  • 基于 context 的请求级超时控制,不修改共享 http.Client 的全局超时
  • 请求级网络控制:代理、自定义 IP / DNS、拨号超时、TLS 配置
  • 支持请求级 Host 覆盖、显式 TLSServerName/SNI 控制,以及结构化 trace 回调 / 摘要
  • 内置重试机制,支持重试次数、退避、抖动、状态码白名单和自定义错误判定
  • 响应体大小限制,避免一次性读取过大内容
  • 错误分类辅助:ClassifyErrorIsTimeoutIsDNSIsTLSIsProxyIsCanceled
  • TLS 嗅探监听 / 拨号工具,适用于 TLS 与明文混合场景
  • ICMP Ping,支持 IPv4 / IPv6 目标和选项化探测

主要能力

HTTP 客户端与请求构建
  • 同时提供 WithXxx 选项和 SetXxx 链式调用两套接口
  • 支持 GetPostPutDeleteHeadPatchOptionsTraceConnect
  • 支持 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 的引用
响应处理
  • 提供 BytesStringJSONReader 等响应体读取接口
  • 支持自动预取响应体
  • 支持按字节数限制响应体读取上限
Ping 模块
  • 提供 PingPingWithContextPingable 以及兼容函数 IsIpPingable
  • PingOptions 支持次数、超时、间隔、截止时间、地址族偏好、源地址、负载长度等参数
  • 对权限不足、协议不支持、超时、解析失败等情况提供明确错误语义

安装

go get b612.me/starnet

快速示例

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
}

行为说明

  • NewClientNewRequest 以及请求构造相关接口在遇到非法选项时会直接返回错误,例如格式不合法的代理地址。
  • NewClientNoErr 是便利构造函数;如果选项校验失败,仍可能返回一个占位 Client,需要严格校验配置时应优先使用 NewClient
  • SetHost / WithHost 只覆盖 HTTP 请求的 Host;如需单独控制 TLS SNI 或证书校验名,应配合 SetTLSServerName / WithTLSServerName 使用。
  • 重试默认仅对幂等方法生效。即使显式关闭“仅幂等方法重试”,通过 SetBodyReaderWithBodyReader 构造的请求在非幂等方法上仍不会自动重试。
  • 当同时使用 proxy + custom IP/DNS 且解析出多个目标地址时,自动目标回退仅对幂等请求生效,以避免重复写入。
  • 绑定到请求上的 TraceRecorder 用于发布已完成请求的摘要;请求执行中的中间状态不保证通过共享 recorder 实时可见。

稳定性说明

  • 原始 ICMP Ping 在部分系统上需要额外权限。
  • 依赖外部网络环境的集成测试结果可能受运行环境影响。

许可证

本项目采用 Apache License 2.0,详见 LICENSE

Documentation

Index

Examples

Constants

View Source
const (
	ContentTypeFormURLEncoded = "application/x-www-form-urlencoded"
	ContentTypeFormData       = "multipart/form-data"
	ContentTypeJSON           = "application/json"
	ContentTypeXML            = "application/xml"
	ContentTypePlain          = "text/plain"
	ContentTypeHTML           = "text/html"
	ContentTypeOctetStream    = "application/octet-stream"
)

HTTP Content-Type 常量

View Source
const (
	DefaultDialTimeout   = 5 * time.Second
	DefaultTimeout       = 10 * time.Second
	DefaultUserAgent     = "starnet"
	DefaultFetchRespBody = false
)

默认配置

Variables

View Source
var (
	// ErrInvalidMethod 无效的 HTTP 方法
	ErrInvalidMethod = errors.New("starnet: invalid HTTP method")

	// ErrInvalidURL 无效的 URL
	ErrInvalidURL = errors.New("starnet: invalid URL")

	// ErrInvalidIP 无效的 IP 地址
	ErrInvalidIP = errors.New("starnet: invalid IP address")

	// ErrInvalidDNS 无效的 DNS 服务器
	ErrInvalidDNS = errors.New("starnet: invalid DNS server")

	// ErrNilClient HTTP Client 为 nil
	ErrNilClient = errors.New("starnet: http client is nil")

	// ErrNilReader Reader 为 nil
	ErrNilReader = errors.New("starnet: reader is nil")

	// ErrFileNotFound 文件不存在
	ErrFileNotFound = errors.New("starnet: file not found")

	// ErrRequestNotPrepared 请求未准备好
	ErrRequestNotPrepared = errors.New("starnet: request not prepared")

	// ErrBodyAlreadyConsumed Body 已被消费
	ErrBodyAlreadyConsumed = errors.New("starnet: response body already consumed")

	// ErrRespBodyTooLarge 响应体超过允许上限
	ErrRespBodyTooLarge = errors.New("starnet: response body too large")

	// ErrPingInvalidTimeout ping 超时参数无效
	ErrPingInvalidTimeout = errors.New("starnet: invalid ping timeout")

	// ErrPingPermissionDenied ping 需要更高权限(raw socket)
	ErrPingPermissionDenied = errors.New("starnet: ping permission denied")

	// ErrPingProtocolUnsupported ping 协议/地址族不受当前平台支持
	ErrPingProtocolUnsupported = errors.New("starnet: ping protocol unsupported")

	// ErrPingNoResolvedTarget ping 目标无法解析为可用地址
	ErrPingNoResolvedTarget = errors.New("starnet: ping target not resolved")
)
View Source
var (
	// ErrNilConn indicates a nil net.Conn argument.
	ErrNilConn = errors.New("starnet: nil connection")

	// ErrTLSSniffFailed indicates TLS sniffing/parsing failed before handshake setup.
	ErrTLSSniffFailed = errors.New("starnet: tls sniff failed")

	// ErrTLSConfigSelectionFailed indicates dynamic TLS config selection failed.
	ErrTLSConfigSelectionFailed = errors.New("starnet: tls config selection failed")

	// ErrNonTLSNotAllowed indicates plain TCP was detected while non-TLS is forbidden.
	ErrNonTLSNotAllowed = errors.New("starnet: non-TLS connection not allowed")

	// ErrNotTLS indicates caller asked for TLS-only object but conn is plain TCP.
	ErrNotTLS = errors.New("starnet: connection is not TLS")

	// ErrNoTLSConfig indicates TLS was detected but no usable TLS config is available.
	ErrNoTLSConfig = errors.New("starnet: no TLS config available")
)

Functions

func BuildPostForm

func BuildPostForm(data map[string]string) []byte

BuildPostForm 构建 POST 表单数据

func BuildQuery

func BuildQuery(data map[string]string) string

BuildQuery 构建查询字符串

func DefaultHTTPClient

func DefaultHTTPClient() *http.Client

DefaultHTTPClient 获取默认 http.Client(单例)

func IsCanceled

func IsCanceled(err error) bool

IsCanceled reports whether err is a cancellation-related error.

func IsDNS

func IsDNS(err error) bool

IsDNS reports whether err is a DNS resolution related error.

func IsIpPingable

func IsIpPingable(ip string, timeout time.Duration, retryLimit int) bool

IsIpPingable keeps backward-compatible bool-only behavior.

func IsProxy

func IsProxy(err error) bool

IsProxy reports whether err is proxy related.

func IsTLS

func IsTLS(err error) bool

IsTLS reports whether err is TLS/Certificate related.

func IsTimeout

func IsTimeout(err error) bool

IsTimeout reports whether err is a timeout-related error.

func Pingable

func Pingable(host string, opts *PingOptions) (bool, error)

Pingable checks host reachability with retry options.

func SetDefaultClient

func SetDefaultClient(client *Client)

SetDefaultClient 设置默认 Client

func SetDefaultHTTPClient

func SetDefaultHTTPClient(client *http.Client)

SetDefaultHTTPClient 设置默认 http.Client

func TLSDefaults

func TLSDefaults() *tls.Config

TLSDefaults returns a TLS config baseline. Caller should set Certificates / GetCertificate as needed.

func UrlDecode

func UrlDecode(str string) (string, error)

UrlDecode URL 解码

func UrlEncode

func UrlEncode(str string) string

UrlEncode URL 编码

func UrlEncodeRaw

func UrlEncodeRaw(str string) string

UrlEncodeRaw URL 编码(空格编码为 %20)

Types

type Body

type Body struct {
	// contains filtered or unexported fields
}

Body 响应体

func (*Body) Bytes

func (b *Body) Bytes() ([]byte, error)

Bytes 获取响应体字节

func (*Body) Close

func (b *Body) Close() error

Close 关闭 Body

func (*Body) IsConsumed

func (b *Body) IsConsumed() bool

IsConsumed 检查是否已消费

func (*Body) JSON

func (b *Body) JSON(v interface{}) error

JSON 解析 JSON 响应

func (*Body) MustBytes

func (b *Body) MustBytes() []byte

MustBytes 获取响应体字节(忽略错误,失败返回 nil)

func (*Body) MustString

func (b *Body) MustString() string

MustString 获取响应体字符串(忽略错误,失败返回空串)

func (*Body) Reader

func (b *Body) Reader() (io.ReadCloser, error)

Reader 获取 Reader(只能调用一次)

func (*Body) String

func (b *Body) String() (string, error)

String 获取响应体字符串

func (*Body) Unmarshal

func (b *Body) Unmarshal(v interface{}) error

Unmarshal 解析 JSON 响应(兼容旧 API)

type BodyConfig

type BodyConfig struct {
	Mode     bodyMode            // 当前 body 来源模式
	Bytes    []byte              // 原始字节
	Reader   io.Reader           // 数据流
	FormData map[string][]string // 表单数据
	Files    []RequestFile       // 文件列表
}

BodyConfig 请求体配置

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client HTTP 客户端封装

func DefaultClient

func DefaultClient() *Client

DefaultClient 获取默认 Client(单例)

func NewClient

func NewClient(opts ...RequestOpt) (*Client, error)

NewClient 创建新的 Client

func NewClientFromHTTP

func NewClientFromHTTP(httpClient *http.Client) (*Client, error)

NewClientFromHTTP 从 http.Client 创建 Client

func NewClientNoErr

func NewClientNoErr(opts ...RequestOpt) *Client

NewClientNoErr 创建新的 Client(忽略错误)。 当 opts 校验失败时,它仍会返回一个可用的 Client 占位对象; 如果调用方需要感知选项错误或依赖默认 starnet Transport 行为,应优先使用 NewClient。

func (*Client) AddOptions

func (c *Client) AddOptions(opts ...RequestOpt) *Client

AddOptions 追加默认选项

func (*Client) Clone

func (c *Client) Clone() *Client

Clone 克隆 Client(深拷贝)

func (*Client) Connect

func (c *Client) Connect(url string, opts ...RequestOpt) (*Response, error)

Connect 发送 CONNECT 请求

func (*Client) Delete

func (c *Client) Delete(url string, opts ...RequestOpt) (*Response, error)

Delete 发送 DELETE 请求

func (*Client) DisableRedirect

func (c *Client) DisableRedirect() *Client

DisableRedirect 禁用重定向

func (*Client) EnableRedirect

func (c *Client) EnableRedirect() *Client

EnableRedirect 启用重定向

func (*Client) Get

func (c *Client) Get(url string, opts ...RequestOpt) (*Response, error)

Get 发送 GET 请求

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"time"

	"b612.me/starnet"
)

func main() {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Client GET"))
	}))
	defer server.Close()

	client := starnet.NewClientNoErr(
		starnet.WithTimeout(10*time.Second),
		starnet.WithUserAgent("MyApp/1.0"),
	)

	resp, err := client.Get(server.URL)
	if err != nil {
		panic(err)
	}
	defer resp.Close()

	body, _ := resp.Body().String()
	fmt.Println(body)
}
Output:
Client GET

func (*Client) HTTPClient

func (c *Client) HTTPClient() *http.Client

HTTPClient 获取底层 http.Client

func (*Client) Head

func (c *Client) Head(url string, opts ...RequestOpt) (*Response, error)

Head 发送 HEAD 请求

func (*Client) NewRequest

func (c *Client) NewRequest(url, method string, opts ...RequestOpt) (*Request, error)

NewRequest 创建新请求

func (*Client) NewRequestWithContext

func (c *Client) NewRequestWithContext(ctx context.Context, url, method string, opts ...RequestOpt) (*Request, error)

NewRequestWithContext 创建新请求(带 context)

func (*Client) NewSimpleRequest

func (c *Client) NewSimpleRequest(url, method string, opts ...RequestOpt) *Request

NewSimpleRequest 创建新请求(忽略错误,支持链式调用)

func (*Client) NewSimpleRequestWithContext

func (c *Client) NewSimpleRequestWithContext(ctx context.Context, url, method string, opts ...RequestOpt) *Request

NewSimpleRequestWithContext 创建新请求(带 context,忽略错误)

func (*Client) Options

func (c *Client) Options(url string, opts ...RequestOpt) (*Response, error)

Options 发送 OPTIONS 请求

func (*Client) Patch

func (c *Client) Patch(url string, opts ...RequestOpt) (*Response, error)

Patch 发送 PATCH 请求

func (*Client) Post

func (c *Client) Post(url string, opts ...RequestOpt) (*Response, error)

Post 发送 POST 请求

func (*Client) Put

func (c *Client) Put(url string, opts ...RequestOpt) (*Response, error)

Put 发送 PUT 请求

func (*Client) RequestOptions

func (c *Client) RequestOptions() []RequestOpt

RequestOptions 获取默认选项(返回副本)

func (*Client) SetDefaultSkipTLSVerify

func (c *Client) SetDefaultSkipTLSVerify(skip bool) *Client

SetDefaultSkipTLSVerify 设置默认跳过 TLS 验证

Example
package main

import (
	"fmt"

	"b612.me/starnet"
)

func main() {
	client := starnet.NewClientNoErr()
	client.SetDefaultSkipTLSVerify(true)

	// All requests from this client will skip TLS verification
	// unless overridden at request level

	fmt.Println("Client configured")
}
Output:
Client configured

func (*Client) SetDefaultTLSConfig

func (c *Client) SetDefaultTLSConfig(tlsConfig *tls.Config) *Client

SetDefaultTLSConfig 设置默认 TLS 配置

func (*Client) SetOptions

func (c *Client) SetOptions(opts ...RequestOpt) *Client

SetOptions 设置默认选项

func (*Client) Trace

func (c *Client) Trace(url string, opts ...RequestOpt) (*Response, error)

Trace 发送 TRACE 请求

type ClientHelloMeta added in v0.4.4

type ClientHelloMeta struct {
	ServerName        string
	LocalAddr         net.Addr
	RemoteAddr        net.Addr
	SupportedProtos   []string
	SupportedVersions []uint16
	CipherSuites      []uint16
}

ClientHelloMeta carries sniffed TLS metadata and connection context.

func (*ClientHelloMeta) Clone added in v0.4.4

func (m *ClientHelloMeta) Clone() *ClientHelloMeta

Clone returns a detached copy safe for callers to mutate.

type Conn

type Conn struct {
	net.Conn
	// contains filtered or unexported fields
}

Conn wraps net.Conn with lazy protocol initialization.

func Dial

func Dial(network, address string) (*Conn, error)

Dial creates a plain TCP starnet.Conn.

func DialTLS

func DialTLS(network, address, certFile, keyFile string) (*Conn, error)

DialTLS creates TLS client conn from cert/key paths.

func DialTLSWithConfig

func DialTLSWithConfig(network, address string, tlsCfg *tls.Config, timeout time.Duration) (*Conn, error)

DialTLSWithConfig creates a TLS client connection wrapper.

func DialWithConfig

func DialWithConfig(network, address string, dc DialConfig) (*Conn, error)

DialWithConfig dials with net.Dialer options.

func (*Conn) ClientHello added in v0.4.4

func (c *Conn) ClientHello() *ClientHelloMeta

ClientHello returns sniffed TLS metadata (if any).

func (*Conn) Close

func (c *Conn) Close() error

func (*Conn) Hostname

func (c *Conn) Hostname() string

Hostname returns sniffed SNI hostname (if any).

func (*Conn) IsTLS

func (c *Conn) IsTLS() bool

func (*Conn) Read

func (c *Conn) Read(b []byte) (int, error)

func (*Conn) SetDeadline

func (c *Conn) SetDeadline(t time.Time) error

func (*Conn) SetReadDeadline

func (c *Conn) SetReadDeadline(t time.Time) error

func (*Conn) SetWriteDeadline

func (c *Conn) SetWriteDeadline(t time.Time) error

func (*Conn) TLSConn

func (c *Conn) TLSConn() (*tls.Conn, error)

func (*Conn) Write

func (c *Conn) Write(b []byte) (int, error)

type DNSConfig

type DNSConfig struct {
	CustomIP   []string                                                     // 直接指定 IP(最高优先级)
	CustomDNS  []string                                                     // 自定义 DNS 服务器
	LookupFunc func(ctx context.Context, host string) ([]net.IPAddr, error) // 自定义解析函数
}

DNSConfig DNS 配置

type DialConfig

type DialConfig struct {
	Timeout   time.Duration
	LocalAddr net.Addr
}

DialConfig controls dialing behavior.

type ErrorKind

type ErrorKind string

ErrorKind is a normalized high-level category for request errors.

const (
	ErrorKindNone     ErrorKind = "none"
	ErrorKindCanceled ErrorKind = "canceled"
	ErrorKindTimeout  ErrorKind = "timeout"
	ErrorKindDNS      ErrorKind = "dns"
	ErrorKindTLS      ErrorKind = "tls"
	ErrorKindProxy    ErrorKind = "proxy"
	ErrorKindOther    ErrorKind = "other"
)

func ClassifyError

func ClassifyError(err error) ErrorKind

ClassifyError maps low-level errors to a stable category for business handling.

type GetConfigForClientFunc

type GetConfigForClientFunc func(hostname string) (*tls.Config, error)

GetConfigForClientFunc selects TLS config by hostname/SNI.

type GetConfigForClientHelloFunc added in v0.4.4

type GetConfigForClientHelloFunc func(hello *ClientHelloMeta) (*tls.Config, error)

GetConfigForClientHelloFunc selects TLS config by sniffed TLS metadata.

type ICMP

type ICMP = pingcore.ICMP

type Listener

type Listener struct {
	net.Listener
	// contains filtered or unexported fields
}

Listener wraps net.Listener and returns starnet.Conn from Accept.

func Listen

func Listen(network, address string) (*Listener, error)

Listen creates a plain listener config (no TLS detection).

func ListenTLS

func ListenTLS(network, address, certFile, keyFile string, allowNonTLS bool) (*Listener, error)

ListenTLS creates TLS listener from cert/key paths.

func ListenWithConfig

func ListenWithConfig(network, address string, cfg ListenerConfig) (*Listener, error)

ListenWithConfig creates a listener with full config.

func ListenWithListenConfig

func ListenWithListenConfig(lc net.ListenConfig, network, address string, cfg ListenerConfig) (*Listener, error)

ListenWithListenConfig creates listener using net.ListenConfig.

func WrapListener

func WrapListener(listener net.Listener, cfg ListenerConfig) (*Listener, error)

func (*Listener) Accept

func (l *Listener) Accept() (net.Conn, error)

func (*Listener) AcceptContext

func (l *Listener) AcceptContext(ctx context.Context) (net.Conn, error)

AcceptContext supports cancellation by closing accepted conn when ctx is done early.

func (*Listener) Config

func (l *Listener) Config() ListenerConfig

Config returns a copy of current config.

func (*Listener) SetConfig

func (l *Listener) SetConfig(cfg ListenerConfig)

SetConfig atomically replaces listener config for new accepted connections.

func (*Listener) Stats

func (l *Listener) Stats() StatsSnapshot

Stats returns current counters snapshot.

type ListenerConfig

type ListenerConfig struct {
	// BaseTLSConfig is used for TLS when dynamic selection returns nil.
	BaseTLSConfig *tls.Config

	// GetConfigForClient selects TLS config for a hostname/SNI.
	// Deprecated: prefer GetConfigForClientHello for richer context.
	GetConfigForClient GetConfigForClientFunc

	// GetConfigForClientHello selects TLS config for sniffed TLS metadata.
	GetConfigForClientHello GetConfigForClientHelloFunc

	// AllowNonTLS allows plain TCP fallback.
	AllowNonTLS bool

	// SniffTimeout bounds protocol sniffing time. 0 means no timeout.
	SniffTimeout time.Duration

	// MaxClientHelloBytes limits buffered sniff data.
	// If <= 0, default 64KiB.
	MaxClientHelloBytes int

	// Logger is optional.
	Logger Logger
}

ListenerConfig controls listener behavior.

func DefaultListenerConfig

func DefaultListenerConfig() ListenerConfig

DefaultListenerConfig returns a conservative default config.

type Logger

type Logger interface {
	Printf(format string, v ...interface{})
}

Logger is a minimal logging abstraction.

type NetworkConfig

type NetworkConfig struct {
	Proxy       string        // 代理地址
	DialTimeout time.Duration // 连接超时
	Timeout     time.Duration // 总超时
	DialFunc    func(ctx context.Context, network, addr string) (net.Conn, error)
}

NetworkConfig 网络配置

type PingOptions

type PingOptions = pingcore.Options

PingOptions controls ping probing behavior.

type PingResult

type PingResult = pingcore.Result

func Ping

func Ping(ip string, seq int, timeout time.Duration) (PingResult, error)

Ping sends one ICMP echo request.

func PingWithContext

func PingWithContext(ctx context.Context, host string, seq int, timeout time.Duration) (PingResult, error)

PingWithContext sends one ICMP echo request with context cancel support.

type Request

type Request struct {
	// contains filtered or unexported fields
}

Request HTTP 请求

func NewRequest

func NewRequest(url, method string, opts ...RequestOpt) (*Request, error)

NewRequest 创建新请求

func NewRequestWithContext

func NewRequestWithContext(ctx context.Context, url, method string, opts ...RequestOpt) (*Request, error)

NewRequestWithContext 创建新请求(带 context)

func NewSimpleRequest

func NewSimpleRequest(url, method string, opts ...RequestOpt) *Request

NewSimpleRequest 创建新请求(忽略错误,支持链式调用)

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"b612.me/starnet"
)

func main() {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("OK"))
	}))
	defer server.Close()

	req := starnet.NewSimpleRequest(server.URL, "GET").
		SetHeader("X-Custom", "value").
		AddQuery("name", "test")

	resp, err := req.Do()
	if err != nil {
		panic(err)
	}
	defer resp.Close()

	fmt.Println(resp.StatusCode)
}
Output:
200

func NewSimpleRequestWithContext

func NewSimpleRequestWithContext(ctx context.Context, url, method string, opts ...RequestOpt) *Request

NewSimpleRequestWithContext 创建新请求(带 context,忽略错误)

func (*Request) AddCookie

func (r *Request) AddCookie(cookie *http.Cookie) *Request

AddCookie 添加 Cookie

func (*Request) AddCookieKV

func (r *Request) AddCookieKV(name, value, path string) *Request

AddCookieKV 添加 Cookie(指定 path)

func (*Request) AddCookies

func (r *Request) AddCookies(cookies map[string]string) *Request

AddCookies 批量添加 Cookies

func (*Request) AddCustomDNS

func (r *Request) AddCustomDNS(dns string) *Request

AddCustomDNS 添加自定义 DNS 服务器

func (*Request) AddCustomIP

func (r *Request) AddCustomIP(ip string) *Request

AddCustomIP 添加自定义 IP

func (*Request) AddFile

func (r *Request) AddFile(formName, filePath string) *Request

AddFile 添加文件(从路径)

func (*Request) AddFileStream

func (r *Request) AddFileStream(formName, fileName string, size int64, reader io.Reader) *Request

AddFileStream 添加文件流

func (*Request) AddFileStreamWithType

func (r *Request) AddFileStreamWithType(formName, fileName, fileType string, size int64, reader io.Reader) *Request

AddFileStreamWithType 添加文件流(指定 MIME 类型)

func (*Request) AddFileWithName

func (r *Request) AddFileWithName(formName, filePath, fileName string) *Request

AddFileWithName 添加文件(指定文件名)

func (*Request) AddFileWithType

func (r *Request) AddFileWithType(formName, filePath, fileType string) *Request

AddFileWithType 添加文件(指定 MIME 类型)

func (*Request) AddFormData

func (r *Request) AddFormData(key, value string) *Request

AddFormData 添加表单数据

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"b612.me/starnet"
)

func main() {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()
		fmt.Fprintf(w, "name=%s", r.FormValue("name"))
	}))
	defer server.Close()

	resp, err := starnet.NewSimpleRequest(server.URL, "POST").
		AddFormData("name", "John").
		AddFormData("age", "30").
		Do()
	if err != nil {
		panic(err)
	}
	defer resp.Close()

	body, _ := resp.Body().String()
	fmt.Println(body)
}
Output:
name=John

func (*Request) AddFormDataMap

func (r *Request) AddFormDataMap(data map[string]string) *Request

AddFormDataMap 批量添加表单数据

func (*Request) AddHeader

func (r *Request) AddHeader(key, value string) *Request

AddHeader 添加 Header

func (*Request) AddHeaders

func (r *Request) AddHeaders(headers map[string]string) *Request

AddHeaders 批量添加 Headers

func (*Request) AddQueries

func (r *Request) AddQueries(queries map[string]string) *Request

AddQueries 批量添加查询参数

func (*Request) AddQuery

func (r *Request) AddQuery(key, value string) *Request

AddQuery 添加查询参数

func (*Request) AddSimpleCookie

func (r *Request) AddSimpleCookie(name, value string) *Request

AddSimpleCookie 添加简单 Cookie(path 为 /)

func (*Request) Client

func (r *Request) Client() *Client

Client 获取关联的 Client(只读)

func (*Request) Clone

func (r *Request) Clone() *Request

Clone 克隆请求

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"b612.me/starnet"
)

func main() {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("OK"))
	}))
	defer server.Close()

	baseReq := starnet.NewSimpleRequest(server.URL, "GET").
		SetHeader("X-API-Key", "secret")

	// Clone and modify
	req1 := baseReq.Clone().AddQuery("page", "1")
	req2 := baseReq.Clone().AddQuery("page", "2")

	resp1, _ := req1.Do()
	resp2, _ := req2.Do()

	defer resp1.Close()
	defer resp2.Close()

	fmt.Println(resp1.StatusCode, resp2.StatusCode)
}
Output:
200 200

func (*Request) Connect

func (r *Request) Connect() (*Response, error)

Connect 发送 CONNECT 请求

func (*Request) Context

func (r *Request) Context() context.Context

Context 获取 context

func (*Request) Cookies

func (r *Request) Cookies() []*http.Cookie

Cookies 获取所有 Cookies

func (*Request) Delete

func (r *Request) Delete() (*Response, error)

Delete 发送 DELETE 请求

func (*Request) DeleteHeader

func (r *Request) DeleteHeader(key string) *Request

DeleteHeader 删除 Header

func (*Request) DeleteQuery

func (r *Request) DeleteQuery(key string) *Request

DeleteQuery 删除查询参数

func (*Request) DeleteQueryValue

func (r *Request) DeleteQueryValue(key, value string) *Request

DeleteQueryValue 删除查询参数的特定值

func (*Request) DisableRawMode

func (r *Request) DisableRawMode() *Request

DisableRawMode 禁用原始模式

func (*Request) DisableRetry

func (r *Request) DisableRetry() *Request

func (*Request) Do

func (r *Request) Do() (*Response, error)

Do 执行请求

func (*Request) EnableRawMode

func (r *Request) EnableRawMode() *Request

EnableRawMode 启用原始模式(不修改请求)

func (*Request) Err

func (r *Request) Err() error

Err 获取累积的错误

func (*Request) Get

func (r *Request) Get() (*Response, error)

Get 发送 GET 请求

func (*Request) GetHeader

func (r *Request) GetHeader(key string) string

GetHeader 获取 Header

func (*Request) HTTPClient

func (r *Request) HTTPClient() (*http.Client, error)

HTTPClient 获取底层 http.Client(只读)

func (*Request) Head

func (r *Request) Head() (*Response, error)

Head 发送 HEAD 请求

func (*Request) Headers

func (r *Request) Headers() http.Header

Headers 获取所有 Headers

func (*Request) Host added in v0.5.0

func (r *Request) Host() string

Host 获取显式 Host 覆盖。

func (*Request) Method

func (r *Request) Method() string

Method 获取 HTTP 方法

func (*Request) Options

func (r *Request) Options() (*Response, error)

Options 发送 OPTIONS 请求

func (*Request) Patch

func (r *Request) Patch() (*Response, error)

Patch 发送 PATCH 请求

func (*Request) Post

func (r *Request) Post() (*Response, error)

Post 发送 POST 请求

func (*Request) Put

func (r *Request) Put() (*Response, error)

Put 发送 PUT 请求

func (*Request) RawRequest

func (r *Request) RawRequest() *http.Request

RawRequest 获取底层 http.Request

func (*Request) ResetCookies

func (r *Request) ResetCookies() *Request

ResetCookies 重置所有 Cookies

func (*Request) ResetHeaders

func (r *Request) ResetHeaders() *Request

ResetHeaders 重置所有 Headers

func (*Request) SetAutoCalcContentLength

func (r *Request) SetAutoCalcContentLength(auto bool) *Request

SetAutoCalcContentLength 设置是否自动计算 Content-Length 警告:启用后会将整个 body 读入内存

func (*Request) SetAutoFetch

func (r *Request) SetAutoFetch(auto bool) *Request

SetAutoFetch 设置是否自动获取响应体

func (*Request) SetBasicAuth

func (r *Request) SetBasicAuth(username, password string) *Request

SetBasicAuth 设置 Basic 认证

func (*Request) SetBearerToken

func (r *Request) SetBearerToken(token string) *Request

SetBearerToken 设置 Bearer Token

func (*Request) SetBody

func (r *Request) SetBody(body []byte) *Request

SetBody 设置请求体(字节)

func (*Request) SetBodyReader

func (r *Request) SetBodyReader(reader io.Reader) *Request

SetBodyReader 设置请求体(Reader)。 出于避免重复写的保守策略,Reader 形态的 body 在非幂等方法上不会自动参与 retry。

func (*Request) SetBodyString

func (r *Request) SetBodyString(body string) *Request

SetBodyString 设置请求体(字符串)

func (*Request) SetContentLength

func (r *Request) SetContentLength(length int64) *Request

SetContentLength 设置 Content-Length

func (*Request) SetContentType

func (r *Request) SetContentType(contentType string) *Request

SetContentType 设置 Content-Type

func (*Request) SetContext

func (r *Request) SetContext(ctx context.Context) *Request

SetContext 设置 context

func (*Request) SetCookies

func (r *Request) SetCookies(cookies []*http.Cookie) *Request

SetCookies 设置所有 Cookies(覆盖)

func (*Request) SetCustomDNS

func (r *Request) SetCustomDNS(dnsServers []string) *Request

SetCustomDNS 设置自定义 DNS 服务器

func (*Request) SetCustomIP

func (r *Request) SetCustomIP(ips []string) *Request

SetCustomIP 设置自定义 IP(直接指定 IP,跳过 DNS)

func (*Request) SetDialFunc

func (r *Request) SetDialFunc(fn func(ctx context.Context, network, addr string) (net.Conn, error)) *Request

SetDialFunc 设置自定义 Dial 函数

func (*Request) SetDialTimeout

func (r *Request) SetDialTimeout(timeout time.Duration) *Request

SetDialTimeout 设置连接超时时间

func (*Request) SetFormData

func (r *Request) SetFormData(data map[string][]string) *Request

SetFormData 设置表单数据(覆盖)

func (*Request) SetHeader

func (r *Request) SetHeader(key, value string) *Request

SetHeader 设置 Header(覆盖)

func (*Request) SetHeaders

func (r *Request) SetHeaders(headers http.Header) *Request

SetHeaders 设置所有 Headers(覆盖)

func (*Request) SetHost added in v0.5.0

func (r *Request) SetHost(host string) *Request

SetHost 设置请求 Host 头覆盖。

func (*Request) SetJSON

func (r *Request) SetJSON(v interface{}) *Request

SetJSON 设置 JSON 请求体

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"b612.me/starnet"
)

func main() {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.Write([]byte(`{"status":"ok"}`))
	}))
	defer server.Close()

	type User struct {
		Name  string `json:"name"`
		Email string `json:"email"`
	}

	user := User{Name: "John", Email: "john@example.com"}

	resp, err := starnet.NewSimpleRequest(server.URL, "POST").
		SetJSON(user).
		Do()
	if err != nil {
		panic(err)
	}
	defer resp.Close()

	var result map[string]string
	resp.Body().JSON(&result)
	fmt.Println(result["status"])
}
Output:
ok

func (*Request) SetLookupFunc

func (r *Request) SetLookupFunc(fn func(ctx context.Context, host string) ([]net.IPAddr, error)) *Request

SetLookupFunc 设置自定义 DNS 解析函数

func (*Request) SetMaxRespBodyBytes

func (r *Request) SetMaxRespBodyBytes(maxBytes int64) *Request

SetMaxRespBodyBytes 设置响应体最大读取字节数(<=0 表示不限制)

func (*Request) SetMethod

func (r *Request) SetMethod(method string) *Request

SetMethod 设置 HTTP 方法

func (*Request) SetProxy

func (r *Request) SetProxy(proxy string) *Request

SetProxy 设置代理

func (*Request) SetQueries

func (r *Request) SetQueries(queries map[string][]string) *Request

SetQueries 设置所有查询参数(覆盖)

func (*Request) SetQuery

func (r *Request) SetQuery(key, value string) *Request

SetQuery 设置查询参数(覆盖)

func (*Request) SetRawRequest

func (r *Request) SetRawRequest(httpReq *http.Request) *Request

SetRawRequest 设置底层 http.Request(启用原始模式)

func (*Request) SetReferer

func (r *Request) SetReferer(referer string) *Request

SetReferer 设置 Referer

func (*Request) SetRetry

func (r *Request) SetRetry(max int, opts ...RetryOpt) *Request

SetRetry 为请求启用自动重试。 默认只重试幂等方法;即使显式关闭幂等限制,Reader 形态的 body 仍会对非幂等方法保持保守禁用, 以避免请求体已落地后再次发送。

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"sync/atomic"

	"b612.me/starnet"
)

func main() {
	var hits int32
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		n := atomic.AddInt32(&hits, 1)
		if n == 1 {
			w.WriteHeader(http.StatusServiceUnavailable)
			return
		}
		w.WriteHeader(http.StatusOK)
	}))
	defer server.Close()

	resp, err := starnet.NewSimpleRequest(server.URL, http.MethodPost).
		SetBodyString("hello"). // 可重放 body 才能安全重试
		SetRetry(1).
		SetRetryIdempotentOnly(false).
		SetRetryBackoff(0, 0, 1).
		SetRetryJitter(0).
		Do()
	if err != nil {
		panic(err)
	}
	defer resp.Close()

	fmt.Println(resp.StatusCode, atomic.LoadInt32(&hits))
}
Output:
200 2

func (*Request) SetRetryBackoff

func (r *Request) SetRetryBackoff(base, max time.Duration, factor float64) *Request

func (*Request) SetRetryIdempotentOnly

func (r *Request) SetRetryIdempotentOnly(enabled bool) *Request

func (*Request) SetRetryJitter

func (r *Request) SetRetryJitter(ratio float64) *Request

func (*Request) SetRetryOnError

func (r *Request) SetRetryOnError(fn func(error) bool) *Request

func (*Request) SetRetryStatuses

func (r *Request) SetRetryStatuses(codes ...int) *Request

func (*Request) SetSkipTLSVerify

func (r *Request) SetSkipTLSVerify(skip bool) *Request

SetSkipTLSVerify 设置是否跳过 TLS 验证

Example
package main

import (
	"fmt"

	"b612.me/starnet"
)

func main() {
	// This example shows how to skip TLS verification
	// Useful for testing with self-signed certificates

	req := starnet.NewSimpleRequest("https://self-signed.example.com", "GET").
		SetSkipTLSVerify(true)

	// In a real scenario, you would call req.Do()
	fmt.Println(req.Method())
}
Output:
GET

func (*Request) SetTLSConfig

func (r *Request) SetTLSConfig(tlsConfig *tls.Config) *Request

SetTLSConfig 设置 TLS 配置

func (*Request) SetTLSServerName added in v0.5.0

func (r *Request) SetTLSServerName(serverName string) *Request

SetTLSServerName 设置显式 TLS ServerName/SNI。

func (*Request) SetTimeout

func (r *Request) SetTimeout(timeout time.Duration) *Request

SetTimeout 设置请求总超时时间 timeout > 0: 为本次请求注入 context 超时 timeout = 0: 不额外设置请求总超时 timeout < 0: 禁用 starnet 默认总超时

func (*Request) SetTraceHooks added in v0.5.0

func (r *Request) SetTraceHooks(hooks *TraceHooks) *Request

SetTraceHooks 设置请求 trace 回调。

func (*Request) SetTraceRecorder added in v0.5.0

func (r *Request) SetTraceRecorder(recorder *TraceRecorder) *Request

SetTraceRecorder 设置请求级 trace 摘要记录器。 记录器会保存最近一次已完成请求的摘要;若多个请求共享同一个记录器,则以最后一次完成的请求为准。

func (*Request) SetTransport

func (r *Request) SetTransport(transport *http.Transport) *Request

SetTransport 设置自定义 Transport

func (*Request) SetURL

func (r *Request) SetURL(urlStr string) *Request

SetURL 设置 URL

func (*Request) SetUploadProgress

func (r *Request) SetUploadProgress(fn UploadProgressFunc) *Request

SetUploadProgress 设置文件上传进度回调

func (*Request) SetUserAgent

func (r *Request) SetUserAgent(userAgent string) *Request

SetUserAgent 设置 User-Agent

func (*Request) Trace

func (r *Request) Trace() (*Response, error)

Trace 发送 TRACE 请求

func (*Request) TraceSummary added in v0.5.0

func (r *Request) TraceSummary() *TraceSummary

TraceSummary 返回当前请求最近一次执行的 trace 摘要快照。

func (*Request) URL

func (r *Request) URL() string

URL 获取 URL

type RequestConfig

type RequestConfig struct {
	Network NetworkConfig
	TLS     TLSConfig
	DNS     DNSConfig
	Body    BodyConfig
	Headers http.Header
	Cookies []*http.Cookie
	Queries map[string][]string

	// 其他配置
	BasicAuth             [2]string          // Basic 认证
	Host                  string             // 显式 Host 头覆盖
	ContentLength         int64              // 手动设置的 Content-Length
	AutoCalcContentLength bool               // 自动计算 Content-Length
	MaxRespBodyBytes      int64              // 响应体最大读取字节数(<=0 表示不限制)
	UploadProgress        UploadProgressFunc // 上传进度回调

	// Transport 配置
	CustomTransport bool            // 是否使用自定义 Transport
	Transport       *http.Transport // 自定义 Transport
}

RequestConfig 请求配置(内部使用)

func (*RequestConfig) Clone

func (c *RequestConfig) Clone() *RequestConfig

Clone 克隆配置

type RequestContext

type RequestContext struct {
	Transport          *http.Transport
	TLSConfig          *tls.Config
	TLSConfigCacheable bool
	TLSServerName      string
	Proxy              string
	CustomIP           []string
	CustomDNS          []string
	DialTimeout        time.Duration
	Timeout            time.Duration
	LookupIPFn         func(ctx context.Context, host string) ([]net.IPAddr, error)
	DialFn             func(ctx context.Context, network, addr string) (net.Conn, error)
}

RequestContext 从 context 中提取的请求配置

type RequestFile

type RequestFile struct {
	FormName string    // 表单字段名
	FileName string    // 文件名
	FilePath string    // 文件路径(如果从文件读取)
	FileData io.Reader // 文件数据流
	FileSize int64     // 文件大小
	FileType string    // MIME 类型
}

RequestFile 表示要上传的文件

type RequestOpt

type RequestOpt func(*Request) error

RequestOpt 请求选项函数

func WithAddCustomDNS

func WithAddCustomDNS(dns string) RequestOpt

WithAddCustomDNS 添加自定义 DNS 服务器

func WithAddCustomIP

func WithAddCustomIP(ip string) RequestOpt

WithAddCustomIP 添加自定义 IP

func WithAddFormData

func WithAddFormData(key, value string) RequestOpt

WithAddFormData 添加表单数据

func WithAutoCalcContentLength

func WithAutoCalcContentLength(auto bool) RequestOpt

WithAutoCalcContentLength 设置是否自动计算 Content-Length

func WithAutoFetch

func WithAutoFetch(auto bool) RequestOpt

WithAutoFetch 设置是否自动获取响应体

func WithBasicAuth

func WithBasicAuth(username, password string) RequestOpt

WithBasicAuth 设置 Basic 认证

func WithBearerToken

func WithBearerToken(token string) RequestOpt

WithBearerToken 设置 Bearer Token

func WithBody

func WithBody(body []byte) RequestOpt

WithBody 设置请求体(字节)

func WithBodyReader

func WithBodyReader(reader io.Reader) RequestOpt

WithBodyReader 设置请求体(Reader)。 出于避免重复写的保守策略,Reader 形态的 body 在非幂等方法上不会自动参与 retry。

func WithBodyString

func WithBodyString(body string) RequestOpt

WithBodyString 设置请求体(字符串)

func WithContentLength

func WithContentLength(length int64) RequestOpt

WithContentLength 设置 Content-Length

func WithContentType

func WithContentType(contentType string) RequestOpt

WithContentType 设置 Content-Type

func WithContext

func WithContext(ctx context.Context) RequestOpt

WithContext 设置 context

func WithCookie

func WithCookie(name, value, path string) RequestOpt

WithCookie 添加 Cookie

func WithCookies

func WithCookies(cookies map[string]string) RequestOpt

WithCookies 批量添加 Cookies

func WithCustomDNS

func WithCustomDNS(dnsServers []string) RequestOpt

WithCustomDNS 设置自定义 DNS 服务器

func WithCustomIP

func WithCustomIP(ips []string) RequestOpt

WithCustomIP 设置自定义 IP

func WithDialFunc

func WithDialFunc(fn func(ctx context.Context, network, addr string) (net.Conn, error)) RequestOpt

WithDialFunc 设置自定义 Dial 函数

func WithDialTimeout

func WithDialTimeout(timeout time.Duration) RequestOpt

WithDialTimeout 设置连接超时时间

func WithFile

func WithFile(formName, filePath string) RequestOpt

WithFile 添加文件

func WithFileStream

func WithFileStream(formName, fileName string, size int64, reader io.Reader) RequestOpt

WithFileStream 添加文件流

func WithFormData

func WithFormData(data map[string][]string) RequestOpt

WithFormData 设置表单数据

func WithFormDataMap

func WithFormDataMap(data map[string]string) RequestOpt

WithFormDataMap 设置表单数据(简化版)

func WithHeader

func WithHeader(key, value string) RequestOpt

WithHeader 设置 Header

func WithHeaders

func WithHeaders(headers map[string]string) RequestOpt

WithHeaders 批量设置 Headers

func WithHost added in v0.5.0

func WithHost(host string) RequestOpt

WithHost 设置显式 Host 头覆盖。

func WithJSON

func WithJSON(v interface{}) RequestOpt

WithJSON 设置 JSON 请求体

func WithLookupFunc

func WithLookupFunc(fn func(ctx context.Context, host string) ([]net.IPAddr, error)) RequestOpt

WithLookupFunc 设置自定义 DNS 解析函数

func WithMaxRespBodyBytes

func WithMaxRespBodyBytes(maxBytes int64) RequestOpt

WithMaxRespBodyBytes 设置响应体最大读取字节数(<=0 表示不限制)

func WithProxy

func WithProxy(proxy string) RequestOpt

WithProxy 设置代理

func WithQueries

func WithQueries(queries map[string]string) RequestOpt

WithQueries 批量添加查询参数

func WithQuery

func WithQuery(key, value string) RequestOpt

WithQuery 添加查询参数

func WithRawRequest

func WithRawRequest(httpReq *http.Request) RequestOpt

WithRawRequest 设置原始请求

func WithRetry

func WithRetry(max int, opts ...RetryOpt) RequestOpt

WithRetry 为请求启用自动重试。 默认只重试幂等方法;即使显式关闭幂等限制,Reader 形态的 body 仍会对非幂等方法保持保守禁用, 以避免请求体已落地后再次发送。

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"sync/atomic"

	"b612.me/starnet"
)

func main() {
	var hits int32
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		n := atomic.AddInt32(&hits, 1)
		if n <= 2 {
			w.WriteHeader(http.StatusServiceUnavailable)
			return
		}
		w.WriteHeader(http.StatusOK)
	}))
	defer server.Close()

	resp, err := starnet.Get(server.URL,
		starnet.WithRetry(2,
			starnet.WithRetryBackoff(0, 0, 1),
			starnet.WithRetryJitter(0),
		),
	)
	if err != nil {
		panic(err)
	}
	defer resp.Close()

	fmt.Println(resp.StatusCode, atomic.LoadInt32(&hits))
}
Output:
200 3

func WithSimpleCookie

func WithSimpleCookie(name, value string) RequestOpt

WithSimpleCookie 添加简单 Cookie(path 为 /)

func WithSkipTLSVerify

func WithSkipTLSVerify(skip bool) RequestOpt

WithSkipTLSVerify 设置是否跳过 TLS 验证

func WithTLSConfig

func WithTLSConfig(tlsConfig *tls.Config) RequestOpt

WithTLSConfig 设置 TLS 配置

func WithTLSServerName added in v0.5.0

func WithTLSServerName(serverName string) RequestOpt

WithTLSServerName 设置显式 TLS ServerName/SNI。

func WithTimeout

func WithTimeout(timeout time.Duration) RequestOpt

WithTimeout 设置请求总超时时间 timeout > 0: 为本次请求注入 context 超时 timeout = 0: 不额外设置请求总超时 timeout < 0: 禁用 starnet 默认总超时

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"time"

	"b612.me/starnet"
)

func main() {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		time.Sleep(100 * time.Millisecond)
		w.Write([]byte("OK"))
	}))
	defer server.Close()

	resp, err := starnet.Get(server.URL,
		starnet.WithTimeout(200*time.Millisecond))
	if err != nil {
		panic(err)
	}
	defer resp.Close()

	fmt.Println(resp.StatusCode)
}
Output:
200

func WithTraceHooks added in v0.5.0

func WithTraceHooks(hooks *TraceHooks) RequestOpt

WithTraceHooks 设置请求 trace 回调。

func WithTraceRecorder added in v0.5.0

func WithTraceRecorder(recorder *TraceRecorder) RequestOpt

WithTraceRecorder 设置请求级 trace 摘要记录器。

func WithTransport

func WithTransport(transport *http.Transport) RequestOpt

WithTransport 设置自定义 Transport

func WithUploadProgress

func WithUploadProgress(fn UploadProgressFunc) RequestOpt

WithUploadProgress 设置文件上传进度回调

func WithUserAgent

func WithUserAgent(userAgent string) RequestOpt

WithUserAgent 设置 User-Agent

type Response

type Response struct {
	*http.Response
	// contains filtered or unexported fields
}

Response HTTP 响应

func Connect

func Connect(url string, opts ...RequestOpt) (*Response, error)

Connect 发送 CONNECT 请求(使用默认 Client)

func Delete

func Delete(url string, opts ...RequestOpt) (*Response, error)

Delete 发送 DELETE 请求(使用默认 Client)

func Get

func Get(url string, opts ...RequestOpt) (*Response, error)

Get 发送 GET 请求(使用默认 Client)

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"b612.me/starnet"
)

func main() {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello, World!"))
	}))
	defer server.Close()

	resp, err := starnet.Get(server.URL)
	if err != nil {
		panic(err)
	}
	defer resp.Close()

	body, _ := resp.Body().String()
	fmt.Println(body)
}
Output:
Hello, World!
func Head(url string, opts ...RequestOpt) (*Response, error)

Head 发送 HEAD 请求(使用默认 Client)

func Options

func Options(url string, opts ...RequestOpt) (*Response, error)

Options 发送 OPTIONS 请求(使用默认 Client)

func Patch

func Patch(url string, opts ...RequestOpt) (*Response, error)

Patch 发送 PATCH 请求(使用默认 Client)

func Post

func Post(url string, opts ...RequestOpt) (*Response, error)

Post 发送 POST 请求(使用默认 Client)

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"b612.me/starnet"
)

func main() {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Posted"))
	}))
	defer server.Close()

	resp, err := starnet.Post(server.URL,
		starnet.WithBodyString("test data"))
	if err != nil {
		panic(err)
	}
	defer resp.Close()

	body, _ := resp.Body().String()
	fmt.Println(body)
}
Output:
Posted

func Put

func Put(url string, opts ...RequestOpt) (*Response, error)

Put 发送 PUT 请求(使用默认 Client)

func Trace

func Trace(url string, opts ...RequestOpt) (*Response, error)

Trace 发送 TRACE 请求(使用默认 Client)

func (*Response) Body

func (r *Response) Body() *Body

Body 获取响应体

func (*Response) Close

func (r *Response) Close() error

Close 关闭响应体

func (*Response) CloseWithClient

func (r *Response) CloseWithClient() error

CloseWithClient 关闭响应体并关闭空闲连接

func (*Response) Request

func (r *Response) Request() *Request

Request 获取原始请求

func (*Response) TraceSummary added in v0.5.0

func (r *Response) TraceSummary() *TraceSummary

TraceSummary 获取当前响应对应的 trace 摘要快照。

type RetryOpt

type RetryOpt func(*retryPolicy) error

func WithRetryBackoff

func WithRetryBackoff(base, max time.Duration, factor float64) RetryOpt

func WithRetryIdempotentOnly

func WithRetryIdempotentOnly(enabled bool) RetryOpt

func WithRetryJitter

func WithRetryJitter(ratio float64) RetryOpt

func WithRetryOnError

func WithRetryOnError(fn func(error) bool) RetryOpt

func WithRetryStatuses

func WithRetryStatuses(codes ...int) RetryOpt

type SniffResult

type SniffResult struct {
	IsTLS       bool
	ClientHello *ClientHelloMeta
	Buffer      *bytes.Buffer
}

SniffResult describes protocol sniffing result.

type Sniffer

type Sniffer interface {
	Sniff(conn net.Conn, maxBytes int) (SniffResult, error)
}

Sniffer detects protocol and metadata from initial bytes.

type Stats

type Stats struct {
	// contains filtered or unexported fields
}

Stats provides lock-free counters.

func (*Stats) Snapshot

func (s *Stats) Snapshot() StatsSnapshot

Snapshot returns a stable view of counters.

type StatsSnapshot

type StatsSnapshot struct {
	Accepted          uint64
	TLSDetected       uint64
	PlainDetected     uint64
	InitFailures      uint64
	SniffFailures     uint64
	TLSConfigFailures uint64
	PlainRejected     uint64
	Closed            uint64
}

StatsSnapshot is a read-only copy of runtime counters.

type TLSConfig

type TLSConfig struct {
	Config     *tls.Config // TLS 配置
	SkipVerify bool        // 跳过证书验证
	ServerName string      // 显式 TLS ServerName/SNI 覆盖
}

TLSConfig TLS 配置

type TLSSniffer

type TLSSniffer struct{}

TLSSniffer is the default sniffer implementation.

func (TLSSniffer) Sniff

func (s TLSSniffer) Sniff(conn net.Conn, maxBytes int) (SniffResult, error)

Sniff detects TLS and extracts SNI when possible.

type TraceCertificateSummary added in v0.5.0

type TraceCertificateSummary struct {
	Subject     string
	Issuer      string
	DNSNames    []string
	IPAddresses []string
}

TraceCertificateSummary 是单张证书的关键信息摘要。

type TraceConnSummary added in v0.5.0

type TraceConnSummary struct {
	Addr       string
	LocalAddr  string
	RemoteAddr string
	Reused     bool
	WasIdle    bool
	IdleTime   time.Duration
}

TraceConnSummary 是连接复用与套接字信息摘要。

type TraceConnectDoneInfo added in v0.5.0

type TraceConnectDoneInfo struct {
	Network string
	Addr    string
	Err     error
}

type TraceConnectStartInfo added in v0.5.0

type TraceConnectStartInfo struct {
	Network string
	Addr    string
}

type TraceConnectSummary added in v0.5.0

type TraceConnectSummary struct {
	Network     string
	Addr        string
	StartedAt   time.Time
	CompletedAt time.Time
	Duration    time.Duration
	Err         error
}

TraceConnectSummary 是单次建连尝试摘要。

type TraceDNSDoneInfo added in v0.5.0

type TraceDNSDoneInfo struct {
	Addrs     []net.IPAddr
	Coalesced bool
	Err       error
}

type TraceDNSStartInfo added in v0.5.0

type TraceDNSStartInfo struct {
	Host string
}

type TraceDNSSummary added in v0.5.0

type TraceDNSSummary struct {
	Host        string
	Addrs       []string
	Coalesced   bool
	StartedAt   time.Time
	CompletedAt time.Time
	Duration    time.Duration
	Err         error
}

TraceDNSSummary 是 DNS 解析摘要。

type TraceGetConnInfo added in v0.5.0

type TraceGetConnInfo struct {
	Addr string
}

type TraceGotConnInfo added in v0.5.0

type TraceGotConnInfo struct {
	Conn     net.Conn
	Reused   bool
	WasIdle  bool
	IdleTime time.Duration
}

type TraceHooks added in v0.5.0

type TraceHooks struct {
	GetConn              func(TraceGetConnInfo)
	GotConn              func(TraceGotConnInfo)
	PutIdleConn          func(TracePutIdleConnInfo)
	DNSStart             func(TraceDNSStartInfo)
	DNSDone              func(TraceDNSDoneInfo)
	ConnectStart         func(TraceConnectStartInfo)
	ConnectDone          func(TraceConnectDoneInfo)
	TLSHandshakeStart    func(TraceTLSHandshakeStartInfo)
	TLSHandshakeDone     func(TraceTLSHandshakeDoneInfo)
	WroteHeaderField     func(TraceWroteHeaderFieldInfo)
	WroteHeaders         func()
	WroteRequest         func(TraceWroteRequestInfo)
	GotFirstResponseByte func()
	RetryAttemptStart    func(TraceRetryAttemptStartInfo)
	RetryAttemptDone     func(TraceRetryAttemptDoneInfo)
	RetryBackoff         func(TraceRetryBackoffInfo)
}

TraceHooks defines optional callbacks for network lifecycle events. Hooks may be called concurrently.

type TracePutIdleConnInfo added in v0.5.0

type TracePutIdleConnInfo struct {
	Err error
}

type TraceRecorder added in v0.5.0

type TraceRecorder struct {
	// contains filtered or unexported fields
}

TraceRecorder 聚合最近一次发布的 trace 摘要。 通过 Request/Client 绑定时,starnet 会为每次执行创建私有运行态并在完成后发布摘要; 直接使用 Hooks() 时,调用方仍需自行管理 Reset 与生命周期。

func NewTraceRecorder added in v0.5.0

func NewTraceRecorder() *TraceRecorder

NewTraceRecorder 创建请求级 trace 记录器。

func (*TraceRecorder) Hooks added in v0.5.0

func (r *TraceRecorder) Hooks() *TraceHooks

Hooks 返回可挂到请求上的底层 trace hooks。

func (*TraceRecorder) Reset added in v0.5.0

func (r *TraceRecorder) Reset()

Reset 清空当前摘要和内部状态。

func (*TraceRecorder) Summary added in v0.5.0

func (r *TraceRecorder) Summary() TraceSummary

Summary 返回当前 trace 摘要的快照。

type TraceRetryAttemptDoneInfo added in v0.5.0

type TraceRetryAttemptDoneInfo struct {
	Attempt     int
	MaxAttempts int
	StatusCode  int
	Err         error
	WillRetry   bool
}

type TraceRetryAttemptStartInfo added in v0.5.0

type TraceRetryAttemptStartInfo struct {
	Attempt     int
	MaxAttempts int
}

type TraceRetryBackoffInfo added in v0.5.0

type TraceRetryBackoffInfo struct {
	Attempt int
	Delay   time.Duration
}

type TraceSummary added in v0.5.0

type TraceSummary struct {
	Method              string
	URL                 string
	StartedAt           time.Time
	ResponseAt          time.Time
	StatusCode          int
	ResponseProto       string
	Conn                TraceConnSummary
	DNS                 *TraceDNSSummary
	DNSEvents           []TraceDNSSummary
	Connect             []TraceConnectSummary
	TLS                 *TraceTLSSummary
	RequestWrittenAt    time.Time
	RequestWriteErr     error
	FirstResponseByteAt time.Time
}

TraceSummary 是一次请求执行的 trace 摘要。

type TraceTLSHandshakeDoneInfo added in v0.5.0

type TraceTLSHandshakeDoneInfo struct {
	Network         string
	Addr            string
	ServerName      string
	ConnectionState tls.ConnectionState
	Err             error
}

type TraceTLSHandshakeStartInfo added in v0.5.0

type TraceTLSHandshakeStartInfo struct {
	Network    string
	Addr       string
	ServerName string
}

type TraceTLSSummary added in v0.5.0

type TraceTLSSummary struct {
	Network            string
	Addr               string
	ServerName         string
	Version            uint16
	VersionName        string
	CipherSuite        uint16
	CipherSuiteName    string
	CurveID            tls.CurveID
	CurveName          string
	NegotiatedProtocol string
	DidResume          bool
	ECHAccepted        bool
	VerifiedChains     int
	StartedAt          time.Time
	CompletedAt        time.Time
	Duration           time.Duration
	Err                error
	PeerCertificates   []TraceCertificateSummary
}

TraceTLSSummary 是 TLS 握手与连接状态摘要。

type TraceWroteHeaderFieldInfo added in v0.5.0

type TraceWroteHeaderFieldInfo struct {
	Key    string
	Values []string
}

type TraceWroteRequestInfo added in v0.5.0

type TraceWroteRequestInfo struct {
	Err error
}

type Transport

type Transport struct {
	// contains filtered or unexported fields
}

Transport 自定义 Transport(支持请求级配置)

func (*Transport) Base

func (t *Transport) Base() *http.Transport

Base 获取基础 Transport

func (*Transport) RoundTrip

func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip 实现 http.RoundTripper 接口

func (*Transport) SetBase

func (t *Transport) SetBase(base *http.Transport)

SetBase 设置基础 Transport

type UploadProgressFunc

type UploadProgressFunc func(filename string, uploaded int64, total int64)

UploadProgressFunc 文件上传进度回调函数

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL