httpjson

package
v0.34.0 Latest Latest
Warning

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

Go to latest
Published: Nov 4, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package httpjson stdlib-only 的 HTTP+JSON 调用纪律单源:ctx 感知构造请求 → 执行 → 限容读体(读错误不吞)→ 状态码检查(错误体 rune 安全截断,不腰斩 UTF-8)→ JSON 解码(out 非 nil 时;out==nil 跳过解码,只判状态码),外加 可选的指数退避重试与服务端 Retry-After 建议捕获。

与 network/httpx 的分工(同名不同物):那侧是 Hertz 底座的服务间调用基础 设施(服务发现/熔断/指标/追踪,编译期即拉 hertz+prometheus+gobreaker+otel 依赖链);本包纯函数、调用方注入 *http.Client——被嵌入的 SDK 与外部 API 调用方(LLM 网关、第三方开放平台)复用,不把微服务全家桶拖进依赖树。 收编自 agentkit/httpx(v0.10.41 起单源在此,agentkit 侧消费本包)。

Index

Constants

View Source
const MaxServerRetryAfter = 5 * time.Minute

MaxServerRetryAfter 服务端退避建议的可信上限:超过 5 分钟的建议不直接采信 (长时间限流应交由上层 failover/切换处置,而非原地等)。

Variables

This section is empty.

Functions

func DoJSON

func DoJSON(ctx context.Context, client *http.Client, req Request, out any) error

DoJSON 执行请求并把 2xx 响应体解码进 out。非 2xx 返回带状态码与响应体摘要 (rune 安全截断到 200 字符)的错误;解码失败返回包装后的解析错误。 错误不带包前缀返回,调用方以自己的包前缀包装一次。

out 为 nil 时**跳过响应体解码**:2xx 即返回 nil。这是 fire-and-forget 调用方 的语义——只关心请求送达与状态码,不关心响应体。此前无条件 json.Unmarshal(raw, nil) 恒定拿到 `json: Unmarshal(nil)` 的 InvalidUnmarshalError ⇒ **服务端已 返回 2xx 的成功请求被误报为失败**,真失败反而淹没在假失败里(#158)。 非 2xx 的判定与 out 无关:照样返回 StatusError(错误体摘要照旧带上)。

out 非 nil 时行为不变:解码失败仍返回「响应解析失败」错误。

func DoJSONWithRetry

func DoJSONWithRetry(ctx context.Context, client *http.Client, reqFn func() (Request, error), cfg RetryConfig, out any) error

DoJSONWithRetry 带重试的 HTTP+JSON 调用。

reqFn 每次尝试重新构造 Request(请求体流不可重读,且调用方可能希望每轮 刷新签名头);reqFn 自身报错视为调用方参数问题,立即返回不重试。 重试间指数退避 + Jitter 抖动;ctx 取消/超时立即返回 ctx.Err()。 配合 WithRetryAfterSink + RetryAfterTransport 可让 429 的服务端建议 参与退避取舍(调用方在 wait 前经 SelectRetryDelay(RetryAfterFrom(ctx)) 采信)。

out 的语义与 DoJSON 完全一致:out==nil 时跳过响应体解码,2xx 即成功返回 (fire-and-forget);非 2xx 仍按可重试判定退避并最终返回 StatusError(#158)。

func RetryAfterFrom

func RetryAfterFrom(ctx context.Context) time.Duration

RetryAfterFrom 读取最近一次 429 的服务端建议(0 = 无)。重试环在计算退避时调用。 sink 不随尝试清除:仅对本次失败确为限流的场景采信(陈旧建议不得套用到 非限流错误上),门控归调用方的重试策略。

func SelectRetryDelay

func SelectRetryDelay(local, hint time.Duration) time.Duration

SelectRetryDelay 退避取舍(「合理性钳制」):服务端建议 >0 且 (≤MaxServerRetryAfter 或 < 本地曲线值)→ 采信建议;否则本地曲线。

func WithRetryAfterSink

func WithRetryAfterSink(ctx context.Context) context.Context

WithRetryAfterSink 在 ctx 注入 sink(重试环上游调用一次;传输层据此回写)。

Types

type RawResponse added in v0.29.0

type RawResponse struct {
	// StatusCode 是 HTTP 状态码(不判 2xx,由调用方按自己的语义映射)。
	StatusCode int
	// Body 是响应体原始字节(最多 limit 字节)。
	Body []byte
	// Truncated 报告 Body 是否因超过 limit 而被截断。
	//
	// 截断本身是刻意的(limit 防内存放大),但**必须可观测**——否则调用方
	// 会把「半截报文」当成完整报文用。
	Truncated bool
}

RawResponse 是 DoRaw 的原始响应结果。

func DoRaw added in v0.28.1

func DoRaw(ctx context.Context, client *http.Client, req Request, limit int64) (RawResponse, error)

DoRaw 执行请求并返回**原始**状态码与响应体:不判 2xx、不解 JSON。

适用面(DoJSON 不适用的那些):

  • 调用方要**按状态码映射自己的语义**(如 404/409 → 各自的哨兵错误);
  • 调用方要把**原文**报文带进错误文案(DoJSON 的错误体是 rune 安全截断到 200 字符的**摘要**,不是原文)。

limit 是读体上限(字节):<=0 时用包级 maxBody。调用方应按自己的报文体量 给一个够用又防内存放大的值(如 8KB)。**超过 limit 的部分会被截断**, 且截断**在 RawResponse.Truncated 里如实标记**——调用方据此判断拿到的是 完整报文还是半截(截断对调用方不可见是最容易埋雷的形态:拿半截 JSON 去 解析会得到难以定位的解析错误,拿半截报文进错误文案会丢服务端说明)。

传输层错误(连不上/超时)返回 err,status/body 无意义;HTTP 层错误(任何状态码) 一律返回 nil err,由调用方按状态码自行判定。

type Request

type Request struct {
	// Method HTTP 方法(空 = GET)。
	Method string
	// URL 完整地址(含 query)。
	URL string
	// Body 请求体(nil = 无请求体;JSON 调用方自行 Marshal)。
	Body []byte
	// Header 鉴权/Content-Type 等请求头注入钩子(可 nil)。
	Header func(h http.Header)
}

Request 一次 HTTP+JSON 调用的描述。

type RetryAfterTransport

type RetryAfterTransport struct {
	Base http.RoundTripper
}

RetryAfterTransport 透明捕获 429 的 Retry-After 头。响应体不做任何改写—— 上层错误构造不受影响。Base 为 nil 时用 http.DefaultTransport。

func (RetryAfterTransport) RoundTrip

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

type RetryConfig

type RetryConfig struct {
	// MaxAttempts 总尝试次数(含首次;<1 视为 1)。
	MaxAttempts int
	// BaseDelay 首次重试延迟(<=0 取 200ms),按尝试轮次指数退避。
	BaseDelay time.Duration
	// MaxDelay 单次重试延迟上限(<=0 取 2s)。
	MaxDelay time.Duration
	// Jitter 随机抖动幅度(防惊群;<0 取 0)。
	Jitter time.Duration
	// Retryable 自定义可重试判定(nil = 默认:网络超时或 HTTP 5xx/429 可重试;
	// 4xx 参数错、响应解析失败不重试)。
	Retryable func(err error) bool
}

RetryConfig 一次重试策略(零值 = 仅执行一次,不重试)。

type StatusError

type StatusError struct {
	Code int
	Body string
}

StatusError 非 2xx 响应错误:供重试判定等按状态码分类(errors.As 提取)。

func (*StatusError) Error

func (e *StatusError) Error() string

Jump to

Keyboard shortcuts

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