Documentation
¶
Overview ¶
Package httpclient provides a reusable outbound HTTP client built on top of net/http.
Client is safe for concurrent use and should normally be created once during application startup. Request is a mutable builder for one logical call and must not be modified or executed concurrently.
The package provides buffered request and response handling, retries, interceptors, request lifecycle callbacks, typed errors, cookie jars and tracing abstractions without depending on a concrete observability library. Business signing, idempotency, service discovery, circuit breaking and notification delivery remain the caller's responsibility.
Index ¶
- Variables
- func IsKind(err error, kind ErrorKind) bool
- type AfterEvent
- type AfterHandler
- type BeforeEvent
- type BeforeHandler
- type Client
- func (c *Client) Clone(opts ...Option) *Client
- func (c *Client) Close() error
- func (c *Client) Delete(ctx context.Context, rawURL string, opts ...RequestOption) (*Response, error)
- func (c *Client) Do(ctx context.Context, req *Request) (resp *Response, err error)
- func (c *Client) Get(ctx context.Context, rawURL string, opts ...RequestOption) (*Response, error)
- func (c *Client) Post(ctx context.Context, rawURL string, opts ...RequestOption) (*Response, error)
- func (c *Client) PostForm(ctx context.Context, rawURL string, values url.Values, opts ...RequestOption) (*Response, error)
- func (c *Client) Put(ctx context.Context, rawURL string, opts ...RequestOption) (*Response, error)
- func (c *Client) R() *Request
- func (c *Client) Request(ctx context.Context, method, rawURL string, opts ...RequestOption) (*Response, error)
- type DataSanitizer
- type Error
- type ErrorKind
- type HTTPAttemptRecord
- type HTTPCallRecord
- type HTTPRequestRecord
- type Handler
- type Interceptor
- type MockResponder
- type Option
- func WithBasicAuth(username, password string) Option
- func WithBearerToken(token string) Option
- func WithCookie(cookie *http.Cookie) Option
- func WithCookieJar(jar http.CookieJar) Option
- func WithDefaultHeader(key, value string) Option
- func WithDefaultHeaders(headers map[string]string) Option
- func WithDefaultQuery(key, value string) Option
- func WithDefaultTimeout(timeout time.Duration) Option
- func WithInterceptor(interceptor Interceptor) Option
- func WithMaxRedirects(maxRedirects int) Option
- func WithProxy(proxy *url.URL) Option
- func WithRetryCondition(condition RetryFunc) Option
- func WithRetryPolicy(policy RetryPolicy) Option
- func WithRoundTripper(rt http.RoundTripper) Option
- func WithTLSConfig(cfg *tls.Config) Option
- func WithTrace(cfg TraceConfig) Option
- func WithTransportConfig(cfg TransportConfig) Option
- type Request
- func (r *Request) AddHeader(key, value string) *Request
- func (r *Request) After(handler AfterHandler) *Request
- func (r *Request) Apply(opts ...RequestOption) error
- func (r *Request) BasicAuth(username, password string) *Request
- func (r *Request) Bearer(token string) *Request
- func (r *Request) Before(handler BeforeHandler) *Request
- func (r *Request) Bytes(data []byte) *Request
- func (r *Request) Cookie(cookie *http.Cookie) *Request
- func (r *Request) Do(ctx context.Context) (*Response, error)
- func (r *Request) Form(values url.Values) *Request
- func (r *Request) Header(key, value string) *Request
- func (r *Request) HeaderMap() http.Header
- func (r *Request) Headers(headers map[string]string) *Request
- func (r *Request) JSON(v any) *Request
- func (r *Request) Method(method string) *Request
- func (r *Request) Mock(responder MockResponder) *Request
- func (r *Request) Queries(values map[string]string) *Request
- func (r *Request) Query(key, value string) *Request
- func (r *Request) Reader(reader io.Reader) *Request
- func (r *Request) Retry(policy RetryPolicy) *Request
- func (r *Request) SkipTrace() *Request
- func (r *Request) String(data string) *Request
- func (r *Request) Timeout(timeout time.Duration) *Request
- func (r *Request) URL(rawURL string) *Request
- func (r *Request) Use(interceptor Interceptor) *Request
- type RequestOption
- func After(handler AfterHandler) RequestOption
- func Before(handler BeforeHandler) RequestOption
- func BytesBody(data []byte) RequestOption
- func FormBody(values url.Values) RequestOption
- func Header(key, value string) RequestOption
- func JSONBody(v any) RequestOption
- func Mock(responder MockResponder) RequestOption
- func Query(key, value string) RequestOption
- func ReaderBody(reader io.Reader) RequestOption
- func Retry(policy RetryPolicy) RequestOption
- func RetryCondition(condition RetryFunc) RequestOption
- func SkipTrace() RequestOption
- func StringBody(data string) RequestOption
- func Timeout(timeout time.Duration) RequestOption
- type RequestSnapshot
- type Response
- type RetryBackoffFunc
- type RetryFunc
- type RetryPolicy
- type Span
- type SpanKind
- type TraceConfig
- type TraceMode
- type TracePropagator
- type Tracer
- type TracerOption
- type TransportConfig
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNilContext 表示请求没有提供上下文。 ErrNilContext = errors.New("http client: nil context") // ErrMissingURL 表示请求未设置 URL。 ErrMissingURL = errors.New("http client: missing request url") // ErrMissingMethod 表示请求未设置 Method。 ErrMissingMethod = errors.New("http client: missing request method") )
Functions ¶
Types ¶
type AfterEvent ¶
type AfterEvent struct {
Request *RequestSnapshot
HTTPRequest *http.Request
Response *Response
Err error
Attempts int
StartedAt time.Time
FinishedAt time.Time
Duration time.Duration
}
AfterEvent 保存请求最终执行结果。
type AfterHandler ¶
type AfterHandler func(ctx context.Context, event *AfterEvent)
AfterHandler 在一次逻辑请求结束后运行。 回调同步执行一次;需要异步处理时,由调用方自行投递。
type BeforeHandler ¶
type BeforeHandler func(ctx context.Context, event *BeforeEvent) error
BeforeHandler 在请求通过本地校验后、进入执行链前运行。 返回错误会终止请求,AfterHandler 仍会收到最终结果。
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client 是一个不可变、并发安全的 HTTP 客户端。 运行期不会原地修改共享配置,适合在高并发环境中长期复用。
func (*Client) Delete ¶
func (c *Client) Delete(ctx context.Context, rawURL string, opts ...RequestOption) (*Response, error)
Delete 是便捷方法。
func (*Client) Get ¶
Get 是便捷方法。
Example ¶
package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"time"
clienthttp "github.com/ClownSketch/httpclient"
)
func main() {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{"status":"ok"}`))
}))
defer server.Close()
client := clienthttp.New(
clienthttp.WithDefaultTimeout(2*time.Second),
clienthttp.WithDefaultHeader("X-Service", "resource"),
)
resp, err := client.Get(context.Background(), server.URL)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(resp.StatusCode, resp.Text())
}
Output: 200 {"status":"ok"}
func (*Client) PostForm ¶
func (c *Client) PostForm(ctx context.Context, rawURL string, values url.Values, opts ...RequestOption) (*Response, error)
PostForm 是表单请求便捷方法。
func (*Client) R ¶
R 创建一个带默认值的请求构建器。
Example ¶
package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"time"
clienthttp "github.com/ClownSketch/httpclient"
)
func main() {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_ = r.ParseForm()
fmt.Println(r.Method, r.Header.Get("Content-Type"), r.Form.Get("name"))
w.WriteHeader(http.StatusCreated)
}))
defer server.Close()
client := clienthttp.New()
resp, err := client.R().
Method(http.MethodPost).
URL(server.URL).
Form(url.Values{"name": []string{"alice"}}).
Timeout(2 * time.Second).
Do(context.Background())
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(resp.StatusCode)
}
Output: POST application/x-www-form-urlencoded alice 201
func (*Client) Request ¶
func (c *Client) Request(ctx context.Context, method, rawURL string, opts ...RequestOption) (*Response, error)
Request 是通用请求入口。
Example ¶
package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
clienthttp "github.com/ClownSketch/httpclient"
)
func main() {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.Method, r.URL.Query().Get("page"), r.Header.Get("X-Request-ID"))
w.WriteHeader(http.StatusOK)
}))
defer server.Close()
client := clienthttp.New()
_, _ = client.Request(
context.Background(),
http.MethodPatch,
server.URL,
clienthttp.Query("page", "1"),
clienthttp.Header("X-Request-ID", "req-001"),
clienthttp.StringBody("patched"),
)
}
Output: PATCH 1 req-001
type DataSanitizer ¶
type DataSanitizer interface {
SanitizeRequest(req *Request) *Request
SanitizeResponse(resp *Response) *Response
}
DataSanitizer 用于按主项目规则处理 trace 请求与响应快照。 httpclient 本身只负责调用,不内置任何脱敏策略。
type Error ¶
type Error struct {
Kind ErrorKind
Op string
Method string
URL string
Attempt int
StatusCode int
Err error
Message string
}
Error 是新客户端的统一错误模型。 它保留了 method/url/attempt 等关键上下文,方便业务层分类处理。
type ErrorKind ¶
type ErrorKind string
ErrorKind 表示 HTTP 客户端错误类别。
const ( ErrorKindInvalidRequest ErrorKind = "invalid_request" ErrorKindBeforeHandler ErrorKind = "before_handler" ErrorKindInterceptor ErrorKind = "interceptor" ErrorKindBuildRequest ErrorKind = "build_request" ErrorKindRequestBodyTooLarge ErrorKind = "request_body_too_large" ErrorKindResponseBodyTooLarge ErrorKind = "response_body_too_large" ErrorKindRedirect ErrorKind = "redirect" ErrorKindNetwork ErrorKind = "network" ErrorKindTimeout ErrorKind = "timeout" ErrorKindCanceled ErrorKind = "canceled" ErrorKindRetryExhausted ErrorKind = "retry_exhausted" ErrorKindResponseRead ErrorKind = "response_read" ErrorKindDecodeResponse ErrorKind = "decode_response" )
type HTTPAttemptRecord ¶
type HTTPAttemptRecord struct {
Attempt int
Method string
StatusCode int
Status string
Headers http.Header
Body []byte
Duration time.Duration
FinishedAt time.Time
Error string
Success bool
}
HTTPAttemptRecord 保存一次实际网络尝试的结果。
type HTTPCallRecord ¶
type HTTPCallRecord struct {
ServiceName string
SpanID string
TraceID string
CallerName string
Request *HTTPRequestRecord
Attempts []*HTTPAttemptRecord
Success bool
Duration time.Duration
Error string
StartedAt time.Time
FinishedAt time.Time
}
HTTPCallRecord 保存一次逻辑 HTTP 调用及其全部尝试。 该结构只描述 HTTP 事实,不包含具体 tracer 的事件字段约定。
func (*HTTPCallRecord) AddAttempt ¶
func (r *HTTPCallRecord) AddAttempt(attempt *HTTPAttemptRecord)
AddAttempt 追加一次实际请求尝试。
func (*HTTPCallRecord) EventData ¶
func (r *HTTPCallRecord) EventData() map[string]any
EventData 返回兼容 tracer external.call 事件结构的数据快照。 自定义追踪系统可以通过 TraceConfig.EventBuilder 使用自己的事件格式。
type HTTPRequestRecord ¶
type HTTPRequestRecord struct {
Method string
URL string
Query string
Headers http.Header
Body []byte
Timeout time.Duration
UserAgent string
Duration time.Duration
StartedAt time.Time
}
HTTPRequestRecord 保存逻辑请求快照。
type Interceptor ¶
Interceptor 用于在发送请求前后扩展行为。
func NewTraceInterceptor ¶
func NewTraceInterceptor(cfg TraceConfig) Interceptor
NewTraceInterceptor 创建一个支持单 span / 多 span 的追踪拦截器。
Example ¶
package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
clienthttp "github.com/ClownSketch/httpclient"
)
func main() {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.Header.Get("X-Trace-ID") != "")
w.WriteHeader(http.StatusOK)
}))
defer server.Close()
tracer := &exampleTracer{}
client := clienthttp.New(
clienthttp.WithTrace(clienthttp.TraceConfig{
Tracer: tracer,
Mode: clienthttp.TraceModeAuto,
}),
)
_, _ = client.Get(context.Background(), server.URL)
}
type exampleTracer struct{}
func (exampleTracer) Start(ctx context.Context, name string, opts ...clienthttp.TracerOption) (context.Context, clienthttp.Span) {
return ctx, exampleSpan{id: "trace-123"}
}
func (exampleTracer) GetSpanFromContext(ctx context.Context) clienthttp.Span {
return nil
}
type exampleSpan struct {
id string
}
func (s exampleSpan) AddEvent(name, eventType string, eventData func() map[string]any) {}
func (s exampleSpan) WithError(err error, message string) {}
func (s exampleSpan) End() {}
func (s exampleSpan) GetSpanTraceID() string {
return s.id
}
Output: true
func RecoverInterceptor ¶
func RecoverInterceptor(handler func(ctx context.Context, req *Request, panicErr error, stack []byte)) Interceptor
RecoverInterceptor 捕获拦截器链中的 panic。
func TraceInterceptor ¶
func TraceInterceptor(tracer Tracer, sanitizer DataSanitizer) Interceptor
TraceInterceptor 使用默认配置创建一个追踪拦截器。 默认模式为 TraceModeAuto,会优先复用父 span,没有父 span 时新建 client span。
type MockResponder ¶
MockResponder 用于请求级 mock。 返回的 Response 会被当前请求链继续消费,因此 tracing / recover 等仍然可用。
type Option ¶
type Option interface {
// contains filtered or unexported methods
}
Option 用于构建 Client。 公开构造函数返回 Option,调用方不需要自行实现。
func WithBasicAuth ¶
WithBasicAuth 配置默认 basic auth。
func WithCookieJar ¶
WithCookieJar 配置由 net/http 管理的 Cookie Jar。 Jar 保存会话状态,Client.Clone 默认共享同一个实例。
func WithDefaultHeader ¶
WithDefaultHeader 配置默认 header。
func WithDefaultHeaders ¶
WithDefaultHeaders 批量配置默认 header。
func WithDefaultQuery ¶
WithDefaultQuery 配置默认 query 参数。
func WithDefaultTimeout ¶
WithDefaultTimeout 配置默认请求超时。
func WithInterceptor ¶
func WithInterceptor(interceptor Interceptor) Option
WithInterceptor 配置客户端级拦截器。
func WithMaxRedirects ¶
WithMaxRedirects 配置最大重定向次数;0 表示不跟随重定向。
func WithRetryCondition ¶
WithRetryCondition 配置默认重试判定函数。
func WithRoundTripper ¶
func WithRoundTripper(rt http.RoundTripper) Option
WithRoundTripper 配置自定义 RoundTripper。 设置后由 RoundTripper 完整接管 TLS、代理和连接池行为,其他传输配置不会应用到它。
func WithTrace ¶
func WithTrace(cfg TraceConfig) Option
WithTrace 使用通用 TraceConfig 注册 tracing 拦截器。 具体 tracing 库的适配逻辑应由主项目完成,再通过这里注入。
func WithTransportConfig ¶
func WithTransportConfig(cfg TransportConfig) Option
WithTransportConfig 使用传入值整体替换底层传输配置。 需要保留默认值时,应从 DefaultTransportConfig 开始修改。
type Request ¶
type Request struct {
// contains filtered or unexported fields
}
Request 是可链式构建的单次请求对象。 Request 构建器不是并发安全对象;每次调用 Client.R 创建独立请求后再执行。
func (*Request) After ¶
func (r *Request) After(handler AfterHandler) *Request
After 设置请求结束回调。 成功、非 2xx 响应及执行错误都会同步调用一次。
func (*Request) Apply ¶
func (r *Request) Apply(opts ...RequestOption) error
Apply 应用 request option。
func (*Request) Before ¶
func (r *Request) Before(handler BeforeHandler) *Request
Before 设置请求执行前守卫。 守卫返回错误时终止请求,After 仍会接收失败结果。
func (*Request) Mock ¶
func (r *Request) Mock(responder MockResponder) *Request
Mock 为当前请求设置 mock responder。
Example ¶
package main
import (
"context"
"fmt"
"net/http"
clienthttp "github.com/ClownSketch/httpclient"
)
func main() {
client := clienthttp.New()
resp, err := client.R().
Method(http.MethodPost).
URL("https://gateway.example.com/pay").
JSON(map[string]any{"amount": 100}).
Mock(func(ctx context.Context, req *clienthttp.Request) (*clienthttp.Response, error) {
return &clienthttp.Response{
StatusCode: http.StatusOK,
Status: "200 OK",
Body: []byte(`{"code":"SUCCESS"}`),
}, nil
}).
Do(context.Background())
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(resp.StatusCode, resp.Text())
}
Output: 200 {"code":"SUCCESS"}
type RequestOption ¶
RequestOption 用于便捷方法中的单次请求配置。
func After ¶
func After(handler AfterHandler) RequestOption
After 配置请求结束回调。
Example ¶
package main
import (
"context"
"fmt"
"net/http"
clienthttp "github.com/ClownSketch/httpclient"
)
func main() {
client := clienthttp.New()
resp, _ := client.Get(
context.Background(),
"https://gateway.example.com/pay",
clienthttp.Mock(func(context.Context, *clienthttp.Request) (*clienthttp.Response, error) {
return &clienthttp.Response{StatusCode: http.StatusBadGateway}, nil
}),
clienthttp.After(func(_ context.Context, event *clienthttp.AfterEvent) {
fmt.Println("failed", event.Failed(), event.Response.StatusCode)
}),
)
fmt.Println("result", resp.StatusCode)
}
Output: failed true 502 result 502
func Mock ¶
func Mock(responder MockResponder) RequestOption
Mock 是一个 RequestOption,用于为当前请求设置 mock responder。
func RetryCondition ¶
func RetryCondition(condition RetryFunc) RequestOption
RetryCondition 是一个 RequestOption,用于覆盖请求级重试判定。
func SkipTrace ¶
func SkipTrace() RequestOption
SkipTrace 是一个 RequestOption,用于跳过本次请求的 tracing interceptor。
type RequestSnapshot ¶
type RequestSnapshot struct {
Method string
URL string
Headers http.Header
Query url.Values
Cookies []*http.Cookie
Body []byte
Timeout time.Duration
Retry RetryPolicy
Mock bool
SkipTrace bool
}
RequestSnapshot 保存生命周期事件中的请求快照。 快照与真实请求相互独立,回调修改快照不会影响请求执行。
type Response ¶
type Response struct {
StatusCode int
Status string
Headers http.Header
Cookies []*http.Cookie
Body []byte
Request *http.Request
Duration time.Duration
Attempt int
}
Response 是对外标准响应。
func (*Response) Decode ¶
Decode 根据响应 Content-Type 将响应体解析到目标值。 Content-Type 缺失或不准确时,会根据 JSON/XML 的首字符进行识别。
Example ¶
package main
import (
"fmt"
"net/http"
clienthttp "github.com/ClownSketch/httpclient"
)
func main() {
resp := &clienthttp.Response{
StatusCode: http.StatusOK,
Headers: http.Header{"Content-Type": []string{"application/json"}},
Body: []byte(`{"status":"ok"}`),
}
var result struct {
Status string `json:"status"`
}
if err := resp.Decode(&result); err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(result.Status)
}
Output: ok
type RetryBackoffFunc ¶
RetryBackoffFunc 计算下一次重试前的等待时间。 attempt 表示刚刚失败的尝试次数,从 1 开始。
type RetryPolicy ¶
type RetryPolicy struct {
MaxAttempts int // 最大尝试次数,包含首次请求;小于等于 0 时只请求一次
BaseDelay time.Duration // 基础延迟时间
MaxDelay time.Duration // 最大退避时间;小于等于 0 时使用 30 秒
ShouldRetry RetryFunc // 重试条件
Backoff RetryBackoffFunc // 自定义退避策略
}
RetryPolicy 定义重试策略。
type Span ¶
type Span interface {
AddEvent(name, eventType string, eventData func() map[string]any)
WithError(err error, message string)
End()
GetSpanTraceID() string
}
Span 用于记录事件与错误。
type SpanKind ¶
type SpanKind int
SpanKind 表示 span 类型。
func SpanKindFromTracerOption ¶
func SpanKindFromTracerOption(opt TracerOption) (SpanKind, bool)
SpanKindFromTracerOption 提取 TracerOption 中的 SpanKind。
type TraceConfig ¶
type TraceConfig struct {
Tracer Tracer
Mode TraceMode
Sanitizer DataSanitizer
Propagator TracePropagator
EventName string
EventType string
EventBuilder func(*HTTPCallRecord) map[string]any
OperationNamer func(*Request) string
ServiceResolver func(*Request) string
CallerName string
CallerResolver func(*Request) string
}
TraceConfig 定义 TraceInterceptor 的行为。
type TracePropagator ¶
TracePropagator 由主项目实现,用于把 trace 上下文注入到请求中。 这让 http 客户端无需直接依赖任何具体 tracing 库。
type Tracer ¶
type Tracer interface {
Start(ctx context.Context, name string, opts ...TracerOption) (context.Context, Span)
GetSpanFromContext(ctx context.Context) Span
}
Tracer 用于抽象追踪系统。
type TransportConfig ¶
type TransportConfig struct {
MaxRedirects int // 最大重定向次数;0 禁止重定向,负数使用 net/http 默认策略
MaxIdleConns int // 全局最大空闲连接数
MaxIdleConnsPerHost int // 单主机最大空闲连接数
MaxConnsPerHost int // 单主机最大连接数;0 不限制
IdleConnTimeout time.Duration // 空闲连接保留时间
TLSHandshakeTimeout time.Duration // TLS 握手超时;0 不限制
DisableKeepAlives bool // 是否禁用连接复用
DisableCompression bool // 是否禁用自动压缩协商
MaxResponseBodySize int64 // 最大响应体字节数;0 不限制
MaxRequestBodySize int64 // 最大请求体字节数;0 不限制
TLSConfig *tls.Config // TLS 配置
Proxy *url.URL // 固定代理地址
RoundTripper http.RoundTripper // 自定义底层传输器;设置后由其完整接管 TLS、代理和连接池行为
Timeout time.Duration // 整个 HTTP 调用超时;0 不限制
}
TransportConfig 用于配置底层连接池与 TLS 行为。
func DefaultTransportConfig ¶
func DefaultTransportConfig() TransportConfig
DefaultTransportConfig 返回库的默认传输配置。 调用方需要整体调整传输层时,应先获取默认值,再修改需要的字段。
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
provider
command
Command provider demonstrates a retryable provider request with caller-supplied data.
|
Command provider demonstrates a retryable provider request with caller-supplied data. |
|
Package factory builds reusable httpclient clients from structured configuration and optional TLS certificate files.
|
Package factory builds reusable httpclient clients from structured configuration and optional TLS certificate files. |