Documentation
¶
Overview ¶
Package httpx 提供 JSON HTTP 客户端。
所有 enjoydream 后端服务共享此包,统一 HTTP 调用方式。
核心特性 ¶
- JSON 请求/响应自动序列化
- Prometheus 指标采集
- 熔断器(gobreaker)
- 指数退避重试
- OpenTelemetry 追踪
- 文件上传(multipart/form-data)
- DoDetail:status + 原始 body(2xx 也返回)
- net/http 桥接层:NewRoundTripper/StdClient——存量标准库调用方一行 Transport 即接入熔断/重试/指标/链路(重试缺省关、显式开)
- WithDialFunc/WithHertzOption:拨号层拦截与 Hertz 原生选项透传(SSRF 防护)
快速接入 ¶
创建客户端:
client := ehttp.NewClient("user-service",
ehttp.WithBaseURL("http://user-service:8080"),
ehttp.WithTimeout(5*time.Second),
ehttp.WithTracePropagation(),
)
GET 请求:
var users []User err := client.GetJSON(ctx, "/api/users", &users)
POST 请求:
var result CreateUserResp err := client.PostJSON(ctx, "/api/users", req, &result)
需要状态码与原始响应体时用 DoDetail(2xx 也返回 body;非 2xx 额外返回 *ServiceError):
status, body, err := client.DoDetail(ctx, http.MethodPost, "/api/users", req)
出站 SSRF 防护 ¶
调用方 URL 来自不受信输入时做两层检查:URL 层字面量拒绝内网 IP/主机名; 拨号层用 WithDialFunc 在建连前校验解析后的 IP(防 DNS rebinding)。 详见 README「出站 SSRF 防护套路」。
监控集成 ¶
使用 WithMetrics 启用 Prometheus 指标:
client := ehttp.NewClient("user-service",
ehttp.WithMetrics(metrics.Registry, "myservice"),
)
指标包括(namespace 未显式指定时前缀为 http_client):
- {ns}_requests_total{service, target, method, status_code}
- {ns}_request_duration_seconds{service, target, method}
- {ns}_requests_in_flight{service, target, method}
同一 Registry + namespace 下创建多个 Client 是安全的:同名指标自动复用 已注册的 collector。禁止 host/IP/port/path 等高基数 label。
熔断器 ¶
使用 WithCircuitBreaker 启用熔断保护:
client := ehttp.NewClient("user-service",
ehttp.WithCircuitBreaker("user-service", gobreaker.Settings{
MaxRequests: 3,
Interval: 10 * time.Second,
Timeout: 30 * time.Second,
}),
)
熔断器状态变化会自动记录到日志。
错误处理 ¶
返回 ServiceError 类型,包含服务名、操作、状态码和响应体:
var svcErr *ehttp.ServiceError
if errors.As(err, &svcErr) {
log.Printf("service: %s, action: %s, code: %d, message: %s",
svcErr.Service, svcErr.Action, svcErr.Code, svcErr.Message)
}
Index ¶
- Variables
- func NewRoundTripper(service string, opts ...ClientOption) http.RoundTripper
- func NodesFromEndpoints(endpoints []string) []loadbalance.Node
- func SafeDialFunc(next network.DialFunc) network.DialFunc
- func SafeDialFuncWith(opts []pkgurlguard.Option, next network.DialFunc) network.DialFunc
- func SelectorNodes(insts []registry.Instance) []loadbalance.Node
- func StdClient(service string, opts ...ClientOption) *http.Client
- func WithPriority(ctx context.Context, priority Priority) context.Context
- type Client
- func (c *Client) Close()
- func (c *Client) DoCodec(ctx context.Context, codecName, method, path string, body any, out any) error
- func (c *Client) DoDetail(ctx context.Context, method, path string, body any) (int, []byte, error)
- func (c *Client) DoJSON(ctx context.Context, method, path string, body any, out any) error
- func (c *Client) DoRaw(ctx context.Context, method, path string, body any) ([]byte, error)
- func (c *Client) GetJSON(ctx context.Context, path string, out any) error
- func (c *Client) Hertz() *client.Client
- func (c *Client) PostJSON(ctx context.Context, path string, body any, out any) error
- func (c *Client) SetTarget(target string)
- func (c *Client) UploadBytes(ctx context.Context, path string, data []byte, fieldName, fileName string, ...) error
- func (c *Client) UploadFile(ctx context.Context, path, filePath, fieldName string, ...) error
- type ClientOption
- func WithBaseURL(u string) ClientOption
- func WithBasicAuth(user, password string) ClientOption
- func WithBearerToken(token string) ClientOption
- func WithCircuitBreaker(name string, settings gobreaker.Settings) ClientOption
- func WithCookieJar(jar http.CookieJar) ClientOption
- func WithDebug() ClientOption
- func WithDialFunc(fn network.DialFunc, dialers ...network.Dialer) ClientOption
- func WithEndpoints(endpoints ...string) ClientOption
- func WithHertzOption(opts ...config.ClientOption) ClientOption
- func WithMetrics(registry prom.Registerer, namespace string) ClientOption
- func WithNNS(serviceName string, nnsClient NNSClient) ClientOption
- func WithOnBeforeRequest(fn func(ctx context.Context, req *protocol.Request) error) ClientOption
- func WithPriorityQueue(capacity int) ClientOption
- func WithRefreshInterval(d time.Duration) ClientOption
- func WithRetryConfig(maxAttempts uint, initDelay, maxDelay, maxJitter time.Duration) ClientOption
- func WithRetryIfFunc(fn func(req *protocol.Request, resp *protocol.Response, err error) bool) ClientOption
- func WithSafeDial(opts ...pkgurlguard.Option) ClientOption
- func WithSelector(sel loadbalance.Selector) ClientOption
- func WithServiceResolver(resolver ServiceResolver) ClientOption
- func WithTLSSkipVerify() ClientOption
- func WithTarget(target string) ClientOption
- func WithTimeout(d time.Duration) ClientOption
- func WithTracePropagation() ClientOption
- type ConsistentHashOption
- type ConsistentHashSelector
- type EndpointManager
- func (m *EndpointManager) GetNodes() []loadbalance.Node
- func (m *EndpointManager) Pick(ctx context.Context, key string) (string, loadbalance.DoneFunc, error)
- func (m *EndpointManager) SetEndpoints(endpoints []string)
- func (m *EndpointManager) SetNodes(nodes []loadbalance.Node)
- func (m *EndpointManager) Stop()
- type InstanceResolver
- type NNSClient
- type NNSResolver
- type Priority
- type PriorityQueue
- type ServiceError
- type ServiceResolver
- type StaticResolver
Constants ¶
This section is empty.
Variables ¶
var ErrCircuitOpen = breaker.ErrCircuitOpen
ErrCircuitOpen 表示熔断器处于打开状态,请求被拒绝。
规范哨兵定义于 concurrency/breaker(错误消息逐字为 "circuit breaker is open"), httpx 此处仅别名它:gobreaker 熔断路径与 adaptive 熔断器(concurrency/breaker) 拒绝时返回同一 sentinel,errors.Is 全链统一判定。判定一律用 errors.Is。
Functions ¶
func NewRoundTripper ¶ added in v0.6.0
func NewRoundTripper(service string, opts ...ClientOption) http.RoundTripper
NewRoundTripper 把 httpx Client 装进标准 http.RoundTripper(#8)。 service 与 opts 语义同 NewClient。
func NodesFromEndpoints ¶ added in v0.4.0
func NodesFromEndpoints(endpoints []string) []loadbalance.Node
NodesFromEndpoints 把字符串端点列表合成为等权节点(权重 1、无元数据)。
func SafeDialFunc ¶ added in v0.7.0
SafeDialFunc 包装 network.DialFunc:出站 SSRF 防护(缺省配置,全阻断)。 next 为 nil 时使用 Hertz 默认 dialer(30s 超时)。需要豁免(测试打本机 mock、内网 webhook 端点)用 SafeDialFuncWith / WithSafeDial 传构造态 option。
func SafeDialFuncWith ¶ added in v0.8.0
SafeDialFuncWith 同 SafeDialFunc,但接受 pkg/urlguard 的构造态 Option:
httpx.SafeDialFuncWith([]urlguard.Option{urlguard.WithAllowPrivate()}, next) // 测试打本机 mock
httpx.SafeDialFuncWith([]urlguard.Option{urlguard.WithAllowCIDRs("10.20.0.0/16")}, next) // 内网端点豁免
CIDR 文法非法时返回的拨号函数一律报错(fail-fast,不带病运行)。
func SelectorNodes ¶ added in v0.4.0
func SelectorNodes(insts []registry.Instance) []loadbalance.Node
SelectorNodes 把注册中心实例切片适配为 Selector 节点(字段闭包映射, 地址补 "http://" 前缀,与历史 endpoint 形态一致)。
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client 是封装了 Hertz HTTP 客户端的高层 HTTP 调用器,支持服务发现、负载均衡、熔断和指标。
func NewClient ¶
func NewClient(service string, opts ...ClientOption) *Client
NewClient 创建 HTTP 客户端实例,应用指定的配置选项。
func (*Client) DoCodec ¶ added in v0.4.0
func (c *Client) DoCodec(ctx context.Context, codecName, method, path string, body any, out any) error
DoCodec 使用指定编解码器发送请求:body 经 codec.Marshal 序列化并设置 对应 Content-Type;响应按其 Content-Type 反查 codec 反序列化到 out (查不到回退请求 codec)。
func (*Client) DoDetail ¶
DoDetail 使用指定的 HTTP 方法发送请求,返回状态码与原始响应体。 与 DoJSON/DoRaw 不同:2xx 也返回原始 body(DoJSON 只把 body 解到 out, DoRaw 仅在成功时返回 body),非 2xx 同时返回 status、body 与 *ServiceError,调用方可自行判定如何处理响应内容。 传输层失败时 status 为 0、body 为 nil。
type ClientOption ¶
type ClientOption func(*Client)
ClientOption 是 Client 的配置函数类型。
func WithBasicAuth ¶
func WithBasicAuth(user, password string) ClientOption
WithBasicAuth 为所有请求设置 Basic Auth 认证。
func WithBearerToken ¶
func WithBearerToken(token string) ClientOption
WithBearerToken 为所有请求设置 Bearer Token 认证。
func WithCircuitBreaker ¶
func WithCircuitBreaker(name string, settings gobreaker.Settings) ClientOption
WithCircuitBreaker 为客户端启用熔断器,使用指定的名称和配置。
func WithCookieJar ¶
func WithCookieJar(jar http.CookieJar) ClientOption
WithCookieJar 为客户端设置 Cookie Jar。 Hertz client 不支持运行时设置 CookieJar;此选项记录警告并忽略。
func WithDebug ¶
func WithDebug() ClientOption
WithDebug 开启调试日志。 Hertz client 不支持运行时调试开关(日志由 hlog 全局控制),此选项留作占位。
func WithDialFunc ¶
func WithDialFunc(fn network.DialFunc, dialers ...network.Dialer) ClientOption
WithDialFunc 注入自定义拨号函数,透传至 Hertz client.WithDialFunc。 典型用途是出站 SSRF 防护的拨号层拦截:在真正建连前校验 addr 解析出的 IP 是否落在内网/黑名单(URL 层字面量检查挡不住 DNS rebinding)。 dialers 可选,用于覆盖 Hertz 默认传输实现。
func WithEndpoints ¶
func WithEndpoints(endpoints ...string) ClientOption
WithEndpoints 设置静态 endpoint 列表。
func WithHertzOption ¶
func WithHertzOption(opts ...config.ClientOption) ClientOption
WithHertzOption 透传任意 Hertz client 配置项(逃生舱)。 优先使用语义化选项(WithTimeout/WithDialFunc/WithRetryConfig 等); 仅当某项 Hertz 能力尚未封装时使用,按传入顺序追加到 client.NewClient 的选项列表尾部。
func WithMetrics ¶
func WithMetrics(registry prom.Registerer, namespace string) ClientOption
WithMetrics 为客户端启用 Prometheus 指标采集。
func WithNNS ¶
func WithNNS(serviceName string, nnsClient NNSClient) ClientOption
WithNNS 启用 NNS 服务发现。
func WithOnBeforeRequest ¶
WithOnBeforeRequest 注册请求前置钩子。 ⚠️ Breaking: 签名从 func(*req.Client, *req.Request) 改为 func(ctx context.Context, req *protocol.Request)(hertz protocol 类型)。
func WithPriorityQueue ¶
func WithPriorityQueue(capacity int) ClientOption
WithPriorityQueue 启用请求优先级队列。
func WithRefreshInterval ¶
func WithRefreshInterval(d time.Duration) ClientOption
WithRefreshInterval 设置 endpoint 刷新间隔。
func WithRetryConfig ¶
func WithRetryConfig(maxAttempts uint, initDelay, maxDelay, maxJitter time.Duration) ClientOption
WithRetryConfig 配置请求重试策略,走 Hertz 官方 client.WithRetryConfig。 参数语义:
- maxAttempts:总尝试次数(>=1,含首次请求);0 = 走 Hertz 默认 1 次
- initDelay:首次重试前的等待时间(指数退避基数,对应 retry.Config.Delay)
- maxDelay:重试延迟上限(避免退避无界增长,retry.Delay 内部封顶)
- maxJitter:随机抖动上限(避免雪崩,对应 retry.Config.MaxJitter)
DelayPolicy 必须显式设置:hertz WithRetryConfig 的默认 DelayPolicy 是 retry.DefaultDelayPolicy(恒返回 0,参见 hertz pkg/app/client/retry/retry.go), 不设置的话 initDelay/maxDelay/maxJitter 三个参数全部无效、重试零等待。 ekit 固定注入 CombineDelay(BackOffDelayPolicy, RandomDelayPolicy): 每次重试延迟 = initDelay<<attempts + [0, maxJitter) 随机抖动,MaxDelay 封顶。
⚠️ 重试触发条件(与 Hertz 默认不同):
Hertz 官方 DefaultRetryIf 仅在网络错误时重试,不重试 5xx 响应(只检查 idempotent 方法 — 参见 vendor 源码 protocol/client/client.go:82)。 ekit WithRetryConfig 默认同时重试 5xx + network error,语义对齐旧 WithRetry(手写 middleware) 行为。如果需要更严格的条件(例如只重试 GET/HEAD/OPTIONS/TRACE/特定状态码),可通过 WithRetryIfFunc 覆盖。
官方依据:https://www.cloudwego.io/zh/docs/hertz/tutorials/basic-feature/client/ (Client 配置表 WithRetryConfig 示例明确列出 retry.WithDelayPolicy; 退避/抖动语义见 hertz pkg/app/client/retry 包:BackOffDelayPolicy = Delay<<attempts, RandomDelayPolicy = fastrand.Int63n(MaxJitter),CombineDelay 求和)
用法:
cli := httpx.NewClient("my-svc",
httpx.WithRetryConfig(3, 100*time.Millisecond, 1*time.Second, 50*time.Millisecond),
)
func WithRetryIfFunc ¶
func WithRetryIfFunc(fn func(req *protocol.Request, resp *protocol.Response, err error) bool) ClientOption
WithRetryIfFunc 覆盖 ekit 默认重试触发条件(5xx + network error), 由用户传更严格的 predicate(例如只对 GET 重试、特定状态码范围等)。 不调 WithRetryIfFunc 时,WithRetryConfig 注入默认 5xx + network error 条件。
func WithSafeDial ¶ added in v0.7.0
func WithSafeDial(opts ...pkgurlguard.Option) ClientOption
WithSafeDial 一步启用出站 SSRF 防护,等价 WithDialFunc(SafeDialFuncWith(opts, nil))。 URL 层字面量校验请另调 pkg/urlguard 的 IsBlockedURL / Guard.CheckURL。 无参调用即缺省全阻断;豁免传 pkg/urlguard 的 Option(可变参,向后兼容无参形态)。
func WithSelector ¶ added in v0.4.0
func WithSelector(sel loadbalance.Selector) ClientOption
WithSelector 设置节点选择器(roundrobin/random/weighted/一致性哈希等, 经 loadbalance.NewSelector 或 NewConsistentHashSelector 构造)。 v0.4.0 起替代 WithBalance。
func WithServiceResolver ¶
func WithServiceResolver(resolver ServiceResolver) ClientOption
WithServiceResolver 设置自定义服务发现解析器。
func WithTracePropagation ¶
func WithTracePropagation() ClientOption
WithTracePropagation 启用 OpenTelemetry 上下文透传(traceparent / tracestate / baggage), 走 Hertz client.UseAsLast 注入,在所有自定义中间件之后执行,
避免 trace 头被其他中间件覆盖或重复。
propagator 通过 otel.GetTextMapPropagator() 读取(默认 W3C TraceContext + Baggage), 与 ekit observability/tracing 全局配置保持一致 — 调用方只需先初始化 tracer + propagator。
官方依据:https://www.cloudwego.io/zh/docs/hertz/tutorials/basic-feature/client/ (UseAsLast 章节:"中间件设置在 ctx.lastMiddleware 中,使用 Use 设置的中间件链存放在 ctx.mws 中,两者相对独立,只是在执行客户端中间件链的最后才执行 ctx.lastMiddleware")
type ConsistentHashOption ¶
type ConsistentHashOption func(*ConsistentHashSelector)
ConsistentHashOption ConsistentHashSelector 的可选参数。
func WithConsistentHashFunc ¶
func WithConsistentHashFunc(fn func([]byte) uint64) ConsistentHashOption
WithConsistentHashFunc 自定义哈希函数(默认 FNV-1a 64)。nil 被忽略。
func WithConsistentReplicas ¶
func WithConsistentReplicas(n int) ConsistentHashOption
WithConsistentReplicas 设置每个节点的虚拟副本数(默认 100)。 n <= 0 被忽略。
type ConsistentHashSelector ¶ added in v0.4.0
type ConsistentHashSelector struct {
// contains filtered or unexported fields
}
ConsistentHashSelector 一致性哈希选择器:同一 key 稳定路由到同一节点, 节点增减仅引起相邻键的重新映射。适合有状态粘滞路由(同用户/同租户 粘住同实例)且实例列表动态变化的场景。
key 取 SelectOption WithKey 值(httpx EndpointManager 默认传请求 PATH); 节点权重按比例折算虚拟副本数(等权均值归一,clamp 到 [1, 4×base]), 注册中心权重配置照常生效。
v0.4.0 起替代 ConsistentHashBalance(BalanceStrategy 形态已删除)。
func NewConsistentHashSelector ¶ added in v0.4.0
func NewConsistentHashSelector(opts ...ConsistentHashOption) (*ConsistentHashSelector, error)
NewConsistentHashSelector 创建一致性哈希选择器。
func (*ConsistentHashSelector) Select ¶ added in v0.4.0
func (b *ConsistentHashSelector) Select(ctx context.Context, nodes []loadbalance.Node, opts ...loadbalance.SelectOption) (loadbalance.Node, loadbalance.DoneFunc, error)
Select 按一致性哈希选择节点。
type EndpointManager ¶
type EndpointManager struct {
// contains filtered or unexported fields
}
EndpointManager endpoint 管理器:动态刷新节点快照 + 缓存降级, 选择经 loadbalance.Selector 完成。
func NewEndpointManager ¶
func NewEndpointManager(resolver ServiceResolver, selector loadbalance.Selector, refreshInterval time.Duration) *EndpointManager
NewEndpointManager 创建 endpoint 管理器。 selector 为 nil 时回退 roundrobin;refreshInterval > 0 且 resolver 非空时 启动刷新循环。
func (*EndpointManager) GetNodes ¶ added in v0.4.0
func (m *EndpointManager) GetNodes() []loadbalance.Node
GetNodes 获取节点快照(优先最新,降级缓存)。
func (*EndpointManager) Pick ¶
func (m *EndpointManager) Pick(ctx context.Context, key string) (string, loadbalance.DoneFunc, error)
Pick 选择一个节点地址,返回地址与结果回写句柄(调用结束后以最终 错误调用 done;done 为 nil 表示无需回写)。 key 用于一致性选点类 Selector(httpx 以请求 PATH 为默认键)。
func (*EndpointManager) SetEndpoints ¶
func (m *EndpointManager) SetEndpoints(endpoints []string)
SetEndpoints 设置静态端点列表(等权合成,停止动态刷新语义不变)。
func (*EndpointManager) SetNodes ¶ added in v0.4.0
func (m *EndpointManager) SetNodes(nodes []loadbalance.Node)
SetNodes 直接设置节点快照。
type InstanceResolver ¶ added in v0.4.0
type InstanceResolver interface {
// ResolveInstances 解析服务名称,返回实例列表。
ResolveInstances(ctx context.Context) ([]registry.Instance, error)
}
InstanceResolver 是 ServiceResolver 的可选增强接口:提供完整实例视图 (含权重与元数据)。EndpointManager 检测到 resolver 实现本接口时, 实例的权重与 Metadata 贯通到 Selector(加权策略与 WithFilter 生效); 仅实现 ServiceResolver 的 resolver 等权合成(权重 1、无元数据)。
type NNSClient ¶
type NNSClient interface {
GetInstances(ctx context.Context, serviceName string) ([]registry.Instance, error)
}
NNSClient NNS 客户端接口,与顶层 nns.NNSClient.GetInstances 签名一致。
type NNSResolver ¶
type NNSResolver struct {
// contains filtered or unexported fields
}
NNSResolver NNS 服务发现解析器(实现 ServiceResolver 与 InstanceResolver)。
func NewNNSResolver ¶
func NewNNSResolver(serviceName string, nnsClient NNSClient) *NNSResolver
NewNNSResolver 创建 NNS 解析器。
func (*NNSResolver) Resolve ¶
func (r *NNSResolver) Resolve(ctx context.Context) ([]string, error)
Resolve 解析服务名称,返回地址列表(丢弃权重与元数据)。
func (*NNSResolver) ResolveInstances ¶ added in v0.4.0
ResolveInstances 解析服务名称,返回实例列表(地址合成 "http://ip:port")。 透传 context 到 NNS,保留超时和 trace_id 语义。
type PriorityQueue ¶
type PriorityQueue struct {
// contains filtered or unexported fields
}
PriorityQueue 分级准入控制队列。
注意语义:这是分级准入控制而非严格优先级队列——high/normal/low 三级 各自独立计数(同级 FIFO),不保证跨级抢占;高优先级请求不会抢占已获准的 低优先级请求,仅在自身级别容量内准入。未知优先级按 PriorityNormal 处理。
func NewPriorityQueue ¶
func NewPriorityQueue(capacity int) *PriorityQueue
NewPriorityQueue 创建优先级队列。
func (*PriorityQueue) Acquire ¶
func (q *PriorityQueue) Acquire(ctx context.Context, priority Priority) bool
Acquire 获取许可(按优先级)。
func (*PriorityQueue) Release ¶
func (q *PriorityQueue) Release(priority Priority)
Release 释放许可。
priority 必须与 Acquire 时一致;未知优先级按 PriorityNormal 释放 (与 Acquire 的 default 分支对齐),避免静默泄漏许可。
type ServiceError ¶
ServiceError 表示 HTTP 服务调用返回的业务错误。
type ServiceResolver ¶
type ServiceResolver interface {
// Resolve 解析服务名称,返回可用的 endpoint 列表。
Resolve(ctx context.Context) ([]string, error)
}
ServiceResolver 服务发现解析器接口。
type StaticResolver ¶
type StaticResolver struct {
// contains filtered or unexported fields
}
StaticResolver 静态 endpoint 解析器。
func NewStaticResolver ¶
func NewStaticResolver(endpoints []string) *StaticResolver
NewStaticResolver 创建静态解析器。
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package codec 提供请求/响应编解码器的注册制抽象(参照 go-kratos encoding)。
|
Package codec 提供请求/响应编解码器的注册制抽象(参照 go-kratos encoding)。 |
|
Package loadbalance 提供与具体服务发现实现解耦的节点选择抽象(Selector, 参照 go-kratos selector)。
|
Package loadbalance 提供与具体服务发现实现解耦的节点选择抽象(Selector, 参照 go-kratos selector)。 |