httpx

package
v1.2.5 Latest Latest
Warning

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

Go to latest
Published: Apr 8, 2026 License: MIT Imports: 18 Imported by: 0

README

httpx

httpx 是面向生产环境的 net/http 封装。它保留原生 HTTP 语义,不引入导入时副作用,并把客户端与服务端生命周期、观测与错误边界明确拆开。

设计原则

  • 客户端和服务端配置分离,避免一个 Config 同时管理两种完全不同的生命周期。
  • 请求与响应使用接近原生 net/http 的无损模型,完整保留多值 Header、多 Cookie、Query 合并与显式 Body 语义。
  • 不在 init() 中注册 Prometheus 指标,指标统一按需懒注册。
  • 所有显式接收 context.Context 的公开方法都要求非 nil context,不静默回退到 context.Background()
  • 不修改调用方传入的 *http.Client / *http.Transport,内部总是克隆后再包裹观测逻辑。
  • 服务端具备显式 Start / Serve / Shutdown / Close 生命周期和 panic recovery。

Client

client := httpx.NewClient(&httpx.ClientConfig{
    Timeout:      5 * time.Second,
    Trace:        true,
    EnableLogger: true,
})

req := &httpx.Request{
    Method: httpx.MethodPost,
    URL:    "https://api.example.com/users?source=micro",
    Query:  url.Values{"expand": {"profile"}},
    Header: http.Header{
        "X-Request-ID": {"req-123"},
    },
}

if err := req.SetJSONBody(map[string]any{
    "name": "alice",
}); err != nil {
    panic(err)
}

resp, err := client.Do(context.Background(), req)
if err != nil {
    panic(err)
}

fmt.Println(resp.StatusCode, resp.Text())

Response 会完整保留 HeaderCookiesBody,并提供:

  • Success() bool
  • Text() string
  • DecodeJSON(dst any) error

指标默认注册到 prometheus.DefaultRegisterer;如果你需要隔离 registry,可以通过 MetricsRegisterer 注入,或者用 DisableMetrics 完全关闭。

Server

server := httpx.NewServer(&httpx.ServerConfig{
    Addr:         ":8080",
    Trace:        true,
    EnableLogger: true,
})

handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", httpx.ContentTypeJSON)
    w.WriteHeader(http.StatusOK)
    _, _ = w.Write([]byte(`{"ok":true}`))
})

go func() {
    if err := server.Start(context.Background(), handler); err != nil {
        panic(err)
    }
}()

defer server.Shutdown(context.Background())

默认行为:

  • 自动暴露健康检查 GET /healthz
  • panic recovery 返回 500 Internal Server Error
  • 只有框架内置的 /healthz/metrics 默认跳过 trace / metrics / access log;禁用健康检查后,你自己的 /healthz 不会被静默跳过
  • Request.Build / Client.Do / Server.Start / Server.Serve / Server.Shutdown 都要求非 nil context
  • Shutdown 在没有 deadline 时会自动应用 ShutdownTimeout

如果你不希望框架接管健康检查,可以设置:

server := httpx.NewServer(&httpx.ServerConfig{
    Addr:                  ":8080",
    DisableHealthEndpoint: true,
})

API 摘要

type Client interface {
    Do(context.Context, *Request) (*Response, error)
    HTTPClient() *http.Client
    CloseIdleConnections()
}

type Server interface {
    Start(context.Context, http.Handler) error
    Serve(context.Context, net.Listener, http.Handler) error
    Shutdown(context.Context) error
    Close() error
    HTTPServer() *http.Server
}

Documentation

Index

Constants

View Source
const (
	ContentTypeJSON           = "application/json"
	ContentTypeFormURLEncoded = "application/x-www-form-urlencoded"
	ContentTypeTextPlain      = "text/plain; charset=utf-8"
	ContentTypeOctetStream    = "application/octet-stream"
)
View Source
const (
	MethodGet     = http.MethodGet
	MethodHead    = http.MethodHead
	MethodPost    = http.MethodPost
	MethodPut     = http.MethodPut
	MethodPatch   = http.MethodPatch
	MethodDelete  = http.MethodDelete
	MethodConnect = http.MethodConnect
	MethodOptions = http.MethodOptions
	MethodTrace   = http.MethodTrace
)

Variables

View Source
var (
	ErrContextRequired            = errors.New("httpx: context is required")
	ErrNilRequest                 = errors.New("httpx: request is required")
	ErrRequestMethodRequired      = errors.New("httpx: request method is required")
	ErrRequestURLRequired         = errors.New("httpx: request url is required")
	ErrRequestAbsoluteURLRequired = errors.New("httpx: request url must be absolute")
	ErrNilResponse                = errors.New("httpx: response is nil")
	ErrNilHandler                 = errors.New("httpx: handler is required")
	ErrNilListener                = errors.New("httpx: listener is required")
	ErrServerAddrRequired         = errors.New("httpx: server addr or listener is required")
	ErrServerAlreadyRunning       = errors.New("httpx: server already running")
)

Functions

This section is empty.

Types

type BasicAuth added in v1.2.2

type BasicAuth struct {
	Username string
	Password string
}

type Client

type Client interface {
	Do(context.Context, *Request) (*Response, error)
	HTTPClient() *http.Client
	CloseIdleConnections()
}

func NewClient added in v1.2.2

func NewClient(conf *ClientConfig) Client

type ClientConfig added in v1.2.2

type ClientConfig struct {
	Logger       *logger.Logger
	EnableLogger bool
	Trace        bool

	Timeout time.Duration

	HTTPClient *http.Client
	Transport  *http.Transport

	CheckRedirect func(*http.Request, []*http.Request) error
	Jar           http.CookieJar

	MaxIdleConns          int
	MaxIdleConnsPerHost   int
	MaxConnsPerHost       int
	IdleConnTimeout       time.Duration
	TLSHandshakeTimeout   time.Duration
	ResponseHeaderTimeout time.Duration
	ExpectContinueTimeout time.Duration

	// ObservabilitySkipPaths skips metrics, tracing, and access logging for
	// matching request paths. Client side defaults to none.
	ObservabilitySkipPaths []string
	MetricsRegisterer      prometheus.Registerer
	DisableMetrics         bool
}

type Request

type Request struct {
	Method string
	URL    string
	Query  url.Values
	Header http.Header
	Body   io.Reader

	Cookies   []*http.Cookie
	BasicAuth *BasicAuth
	Host      string
}

func (*Request) AddCookie added in v1.2.2

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

func (*Request) AddHeader added in v1.2.2

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

func (*Request) Build added in v1.2.2

func (r *Request) Build(ctx context.Context) (*http.Request, error)

func (*Request) SetBody added in v1.2.2

func (r *Request) SetBody(contentType string, body []byte)

func (*Request) SetFormBody added in v1.2.2

func (r *Request) SetFormBody(values url.Values)

func (*Request) SetHeader added in v1.2.2

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

func (*Request) SetJSONBody added in v1.2.2

func (r *Request) SetJSONBody(value any) error

type RequestSnapshot added in v1.2.2

type RequestSnapshot struct {
	Method string
	URL    string
	Header http.Header
	Host   string
}

type Response

type Response struct {
	StatusCode int
	Status     string
	Header     http.Header
	Cookies    []*http.Cookie
	Body       []byte
	Duration   time.Duration
	Request    *RequestSnapshot
}

func (*Response) DecodeJSON added in v1.2.2

func (r *Response) DecodeJSON(dst any) error

func (*Response) Success

func (r *Response) Success() bool

func (*Response) Text added in v1.2.2

func (r *Response) Text() string

type Server added in v1.0.7

type Server interface {
	Start(context.Context, http.Handler) error
	Serve(context.Context, net.Listener, http.Handler) error
	Shutdown(context.Context) error
	Close() error
	HTTPServer() *http.Server
}

func NewServer added in v1.0.7

func NewServer(conf *ServerConfig) Server

type ServerConfig added in v1.2.2

type ServerConfig struct {
	Addr     string
	Listener net.Listener

	Logger       *logger.Logger
	EnableLogger bool
	Trace        bool

	ReadTimeout       time.Duration
	ReadHeaderTimeout time.Duration
	WriteTimeout      time.Duration
	IdleTimeout       time.Duration
	ShutdownTimeout   time.Duration

	// ObservabilitySkipPaths skips metrics, tracing, and access logging for
	// matching request paths. /metrics is always skipped; the default health
	// path is skipped only when the framework-managed health endpoint is enabled.
	ObservabilitySkipPaths []string
	MetricsRegisterer      prometheus.Registerer
	DisableMetrics         bool

	DisableHealthEndpoint bool
	HealthPath            string
	HealthHandler         http.Handler
}

Jump to

Keyboard shortcuts

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