httpx

package
v2.2.44 Latest Latest
Warning

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

Go to latest
Published: Sep 22, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

README

exception/httpx

把 *exception.ApiException 写到 HTTP 响应:net/http、Gin、Fiber、go-restful 全覆盖。

概述

本包统一负责:

  • 把任意 error / *ApiException 写入响应体(JSON);
  • 根据 ApiException.HttpCode 设置响应状态码;
  • 在中间件 / 全局异常处理器中捕获 panic 并按 500 序列化;
  • 处理 404 / 405 与全局错误处理器;
  • 根据 Accept-Language 选用中英文 Reason 文案;
  • 提供 *http.RoundTripper 装饰器透传 trace 信息。

安装

go get gitee.com/hexug/go-tools/v2/exception/httpx

框架适配速查

框架 写 JSON 写错误 中间件 NotFound / 错误处理器
net/http WriteJSON / WriteJSONStatus WriteError / WriteErrorFromError HTTPMiddleware() HTTPNotFoundHandler / HTTPMethodNotAllowedHandler / HTTPWithNotFound
Gin GinWriteJSON / GinWriteJSONStatus GinWriteError / GinWriteErrorFromError GinMiddleware() GinNotFoundHandler / GinMethodNotAllowedHandler / UseGinNotFound
Fiber v3 FiberWriteJSON / FiberWriteJSONStatus FiberWriteError / FiberWriteErrorFromError FiberMiddleware() FiberNotFoundHandler / FiberErrorHandler
go-restful RestfulWriteJSON / RestfulWriteJSONStatus RestfulWriteError / RestfulWriteErrorFromError RestfulFilter() RestfulServiceErrorHandler

快速开始

四个框架共用相同骨架:注册中间件(panic 兜底 + 错误序列化)→ 注册 404 / 405 兜底 → 业务 handler 中调用 XxxWriteError 写错误响应。下面按框架各给一段最小示例。

net/http

通过两层 http.Handler 装饰把中间件与 NotFound 兜底链起来;mux 仍负责正常路由分发。

import (
    "net/http"

    "gitee.com/hexug/go-tools/v2/exception"
    "gitee.com/hexug/go-tools/v2/exception/httpx"
)

mux := http.NewServeMux()
mux.HandleFunc("/users/", func(w http.ResponseWriter, r *http.Request) {
    // 业务校验失败时写入 ApiException,httpx 自动设置 HTTP 状态码与 JSON 响应体
    httpx.WriteError(w, r, exception.NewBadRequest("缺少 id 参数"))
})

// HTTPWithNotFound 包裹 mux:未命中路由时按 ApiException 风格返回 404 / 405
// HTTPMiddleware 包在最外层:捕获下游 panic 并以 500 序列化
handler := httpx.HTTPMiddleware()(httpx.HTTPWithNotFound(mux))
_ = http.ListenAndServe(":8080", handler)
Gin

UseGinNotFound 是 NoRoute + NoMethod 的一键装配,等价于分别调用 GinNotFoundHandler / GinMethodNotAllowedHandler。

import (
    "github.com/gin-gonic/gin"

    "gitee.com/hexug/go-tools/v2/exception"
    "gitee.com/hexug/go-tools/v2/exception/httpx"
)

r := gin.New()
r.Use(httpx.GinMiddleware()) // panic 兜底 + 写 ApiException 响应体
httpx.UseGinNotFound(r)      // 一键装配 404 / 405 兜底

r.GET("/users/:id", func(c *gin.Context) {
    // 直接写业务错误;httpx 会按 ApiException 的 HttpCode 设置响应状态
    httpx.GinWriteError(c, exception.NewNotFound("用户不存在"))
})
Fiber v3

Fiber v3 的 NotFound 用 app.Use 注册一个兜底中间件即可;FiberErrorHandler 在 fiber.New(fiber.Config{...}) 里挂上,处理 handler 内返回的 error。

import (
    "github.com/gofiber/fiber/v3"

    "gitee.com/hexug/go-tools/v2/exception"
    "gitee.com/hexug/go-tools/v2/exception/httpx"
)

app := fiber.New(fiber.Config{
    ErrorHandler: httpx.FiberErrorHandler(), // handler 返回 error 时统一按 ApiException 序列化
})
app.Use(httpx.FiberMiddleware())  // panic 兜底 + 错误响应
app.Use(httpx.FiberNotFoundHandler()) // 必须放到最后,所有未命中路由会落到此处

app.Get("/users/:id", func(c fiber.Ctx) error {
    // FiberWriteError 返回 error,便于 handler 直接 return
    return httpx.FiberWriteError(c, exception.NewNotFound("用户不存在"))
})
go-restful

go-restful 的全局兜底通过 Container.ServiceErrorHandler + Filter 组合实现;RestfulFilter 提供 panic 兜底,RestfulServiceErrorHandler 处理框架抛出的 ServiceError。

import (
    restful "github.com/emicklei/go-restful/v3"

    "gitee.com/hexug/go-tools/v2/exception"
    "gitee.com/hexug/go-tools/v2/exception/httpx"
)

container := restful.NewContainer()
container.Filter(httpx.RestfulFilter())                       // panic 兜底
container.ServiceErrorHandler(httpx.RestfulServiceErrorHandler()) // 路由级错误统一处理

ws := new(restful.WebService)
ws.Route(ws.GET("/users/{id}").To(func(req *restful.Request, resp *restful.Response) {
    // RestfulWriteError 直接写响应,无返回值
    httpx.RestfulWriteError(req, resp, exception.NewNotFound("用户不存在"))
}))
container.Add(ws)
成功响应统一 JSON 包装

业务正常返回也走 httpx.XxxWriteJSON,可保证成功 / 失败响应使用一致的序列化策略(同一套 JSON 编码、同一套 trace 字段透传)。

import (
    "github.com/gin-gonic/gin"

    "gitee.com/hexug/go-tools/v2/exception/httpx"
)

r := gin.New()
r.GET("/users/:id", func(c *gin.Context) {
    user := map[string]any{"id": c.Param("id"), "name": "alice"}
    // 默认 200 状态码;如需自定义状态码用 GinWriteJSONStatus
    httpx.GinWriteJSON(c, user)
})
客户端透传 trace 字段

NewTracingRoundTripper 用于将当前请求 ctx 中的追踪字段(如 request_id)透传到下游 HTTP 调用的请求头,便于跨服务链路串联。

import (
    "net/http"

    "gitee.com/hexug/go-tools/v2/exception/httpx"
)

// Transport 装饰即可生效,无需修改业务调用代码
cli := &http.Client{
    Transport: httpx.NewTracingRoundTripper(http.DefaultTransport),
}

req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "http://downstream/api", nil)
resp, err := cli.Do(req) // 下游收到的请求头会带上 ctx 中的追踪字段
_ = resp
_ = err

API 概览

net/http
func WriteJSON(w http.ResponseWriter, r *http.Request, data any)
func WriteJSONStatus(w http.ResponseWriter, r *http.Request, status int, data any)
func WriteError(w http.ResponseWriter, r *http.Request, err *exception.ApiException)
func WriteErrorFromError(w http.ResponseWriter, r *http.Request, err error)
func HTTPMiddleware() func(http.Handler) http.Handler
func HTTPNotFoundHandler() http.Handler
func HTTPMethodNotAllowedHandler() http.Handler
func HTTPWithNotFound(next http.Handler) http.Handler
Gin
func GinWriteJSON(c *gin.Context, data any)
func GinWriteJSONStatus(c *gin.Context, status int, data any)
func GinWriteError(c *gin.Context, err *exception.ApiException)
func GinWriteErrorFromError(c *gin.Context, err error)
func GinMiddleware() gin.HandlerFunc
func GinNotFoundHandler() gin.HandlerFunc
func GinMethodNotAllowedHandler() gin.HandlerFunc
func UseGinNotFound(engine *gin.Engine)
Fiber v3
func FiberWriteJSON(c fiber.Ctx, data any) error
func FiberWriteJSONStatus(c fiber.Ctx, status int, data any) error
func FiberWriteError(c fiber.Ctx, err *exception.ApiException) error
func FiberWriteErrorFromError(c fiber.Ctx, err error) error
func FiberMiddleware() fiber.Handler
func FiberNotFoundHandler() fiber.Handler
func FiberErrorHandler() fiber.ErrorHandler
go-restful
func RestfulWriteJSON(req *restful.Request, resp *restful.Response, data any)
func RestfulWriteJSONStatus(req *restful.Request, resp *restful.Response, status int, data any)
func RestfulWriteError(req *restful.Request, resp *restful.Response, err *exception.ApiException)
func RestfulWriteErrorFromError(req *restful.Request, resp *restful.Response, err error)
func RestfulFilter() restful.FilterFunction
func RestfulServiceErrorHandler() restful.ServiceErrorHandleFunction
通用
func FromError(err error) *exception.ApiException        // 非 ApiException 包装为 500
func NewTracingRoundTripper(base http.RoundTripper) *TracingRoundTripper

注意事项

  • 中间件统一捕获 panic:将 recover() 的值包装为 *ApiException(500),写入响应体;
  • 写入响应时使用 ApiException.GetHttpCode(),永不越界到非法状态码;
  • Accept-Language: en / lang=en 等会触发英文 Reason 输出(多语言机制详见 lang.go);
  • 注册 NotFound 处理器后,框架会按 *ApiException 风格返回 404 / 405,避免空响应;
  • NewTracingRoundTripper 主要用于将 trace 字段透传给下游 HTTP 服务,不属于错误处理但对追踪有帮助。

Documentation

Overview

client.go 提供 HTTP 客户端侧的 Request ID 透传能力。

使用方式(推荐):

client := &http.Client{
    Transport: httpx.NewTracingRoundTripper(http.DefaultTransport),
}
// 业务代码:把带有 request_id 的 ctx 传给请求,自动加到 Header
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
resp, _ := client.Do(req)

Package httpx —— HTTP 框架统一的 panic / error 恢复中间件。

中间件职责:

  1. 捕获 handler 中抛出的 panic,统一封装成 500 ApiException
  2. 捕获 handler 通过各框架原生机制返回的 error(如 c.Error / chain 错误)
  3. 所有错误响应都通过 Write*Error 走统一协议,自动携带 request_id

中间件顺序建议(以 Gin 为例):

r := gin.New()
r.Use(tracemw.Gin(trace.DefaultConfig())) // 1) 先注入 request_id
r.Use(httpx.GinMiddleware())              // 2) 再做 panic 恢复
r.Use(loggingMiddleware)                  // 3) 业务日志

Package httpx 内的语言协商辅助:把 HTTP Accept-Language 头归一化为 exception 包支持的内部语言标签(exception.LangZH / exception.LangEN)。

解析策略:

  1. 按 "," 拆分出多个语言项;
  2. 解析每一项的 "q=" 权重(缺省视为 1.0);
  3. 按权重降序排序,取第一条能够识别的语言;
  4. 均不能识别时退回默认语言(LangZH)。

只识别主语言标签的前缀(例如 "en-US" 归一化为 "en"),避免维护一张冗长的 语言子标签表;对于未知语言统一回退中文,保证行为可预期。

Package httpx —— 各 HTTP 框架 404/405 兜底处理器。

背景:

Gin / net/http / go-restful 等框架对于未注册的路由,会直接返回
纯文本 "404 page not found",不会经过业务中间件链。这导致:
  - 响应体不符合统一 Response 协议(缺 code/request_id/server_time)
  - 客户端需要额外写一套 404 解析逻辑
  - 排障时缺失 request_id,难以串联日志

本文件统一提供兜底 Handler,将 404/405 也纳入统一响应协议。

各框架接入方式(建议放在所有路由注册之后):

// Gin —— 推荐使用一键装配,避免漏开 HandleMethodNotAllowed 开关
httpx.UseGinNotFound(r)

// Gin —— 手动装配(必须显式打开 HandleMethodNotAllowed,否则 405 会退化为 404)
r.HandleMethodNotAllowed = true
r.NoRoute(httpx.GinNotFoundHandler())
r.NoMethod(httpx.GinMethodNotAllowedHandler())

// Fiber v3 —— 推荐在 fiber.New 时通过配置注入全局 ErrorHandler
// 它能同时接管 Fiber 自己抛出的 404/405 错误(这些错误不走业务中间件链,仅走 ErrorHandler)
app := fiber.New(fiber.Config{
	ErrorHandler: httpx.FiberErrorHandler(),
})

// Fiber v3 —— 兼容方式(作为最后一个 Use,仅能拦截路由未命中的 404,
// 无法拦截 Fiber 内部的 405/501 等早期错误)
app.Use(httpx.FiberNotFoundHandler())

// go-restful(Container 级别)
// ⚠️ 必须使用 restful.NewContainer(),不能用 restful.DefaultContainer!
// DefaultContainer 内部使用 http.DefaultServeMux,完全未注册的路径会被
// DefaultServeMux 直接返回 "404 page not found",根本不进 go-restful 的
// dispatch,ServiceErrorHandler 永远拦截不到。
// NewContainer() 会把 "/" 注册为兜底路由,所有请求都先进 dispatch,
// ServiceErrorHandler 才能正确拦截 404。
container := restful.NewContainer()
container.ServiceErrorHandler(httpx.RestfulServiceErrorHandler())
// 若实在必须用 DefaultContainer,可在最外层套 HTTPWithNotFound 兜底:
// http.ListenAndServe(":8080", httpx.HTTPWithNotFound(restful.DefaultContainer))

// net/http(Go 1.22+)
mux := http.NewServeMux()
// ... 注册业务路由 ...
// HTTPWithNotFound 会同时拦截下游的 404 和 405碰撦,改成统一协议输出
http.ListenAndServe(":8080", httpx.HTTPWithNotFound(mux))

关于 gRPC:

gRPC 调用不存在的方法时,框架会直接返回 codes.Unimplemented,
**服务端拦截器链完全不会被触发**,这是 gRPC 协议层决定的,
无法在服务端通过中间件兜底。建议在客户端拦截器里统一处理,
或在网关层(如 grpc-gateway)统一包装。详见 README。

Package httpx 提供 HTTP 场景下的统一响应协议与响应写入能力。

统一响应协议(所有成功 / 失败响应共用同一结构):

{
    "code":        0,                  // 0 表示成功;非 0 为业务/HTTP 错误码
    "message":     "xxx",              // 错误信息(成功时可省略)
    "data":        {...},              // 业务数据(失败时可省略)
    "request_id":  "Xk2_...nano...",   // 本次请求的追踪 ID
    "server_time": 1714982400           // 服务端生成响应时的 Unix 秒时间戳
}

设计要点:

  1. 所有框架(Gin / Fiber / go-restful / net-http)提供风格一致的 WriteJSON / WriteError 入口
  2. request_id 自动从 ctx 中读取(需先挂载 logger/trace 中间件)
  3. 错误路径与成功路径共用同一结构,客户端只需一套解析逻辑
  4. 即使 trace 中间件未挂载,依然可正常工作(request_id 字段为空)

Package httpx 的 sanitizer.go:错误响应出口的全局脱敏钩子。

背景:ApiException.Message 可能携带后端引擎(docker daemon / containerd / registry 等)的原始错误文本,其中可能包含 socket 路径、主机 IP、文件系统 路径等基础设施信息。服务方通常希望"响应只给方向,全文留在日志"。

本钩子提供统一收口:所有框架(Gin / Fiber / go-restful / net-http)的 Write*Error 系列入口在把错误序列化为统一 Response 之前,都会先经过该钩子。

典型用法(服务启动时注册一次):

httpx.SetErrorSanitizer(func(ctx context.Context, err *exception.ApiException, requestID string) *exception.ApiException {
    if err.GetHttpCode() >= 500 {
        clone := *err
        clone.Message = "服务内部错误,请稍后重试"
        return &clone
    }
    return err
})

设计约束:

  1. 钩子不得修改入参 err(需要改动时请克隆后返回),避免污染调用方 / 日志记录;
  2. 钩子应快速返回(位于错误响应热路径);
  3. 钩子返回 nil 视为"不修改",按原 err 输出;
  4. 钩子 panic 不阻断错误响应:恢复后按原 err 输出。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FiberErrorHandler

func FiberErrorHandler() fiber.ErrorHandler

FiberErrorHandler 返回一个 Fiber v3 的全局错误处理器,用于注入 fiber.Config.ErrorHandler。

背景:Fiber 内部在路由匹配阶段就可能抛出 ErrNotFound(404)/ ErrMethodNotAllowed(405)/ErrRequestTimeout 等错误,这些错误**不会进入**业务 中间件链(即 FiberMiddleware 也接不到),仅由全局 app.ErrorHandler 处理。 如果不替换默认的 DefaultErrorHandler,就会直接输出纯文本状态码,破坏统一协议。

使用:

app := fiber.New(fiber.Config{
	ErrorHandler: httpx.FiberErrorHandler(),
})
app.Use(tracemw.Fiber(nil))
app.Use(httpx.FiberMiddleware())
// ... 注册业务路由 ...

func FiberMiddleware

func FiberMiddleware() fiber.Handler

FiberMiddleware 统一处理 fiber v3 中的 panic 与 handler 返回错误

使用方式:

app := fiber.New()
app.Use(httpx.FiberMiddleware())

func FiberNotFoundHandler

func FiberNotFoundHandler() fiber.Handler

FiberNotFoundHandler 返回 Fiber v3 的 404 兜底 Handler

使用(放在所有路由注册之后,作为最后一个 Use):

app.Use(httpx.FiberNotFoundHandler())

⚠️ 这种方式只能接管“路由完全未命中”的场景,无法拦截 Fiber 自己抛出的 ErrMethodNotAllowed(405)或 StatusNotImplemented(501)等前置错误—— 这些错误是由 Fiber 在路由分发阶段直接交给全局 app.ErrorHandler 的, 根本不会进入业务中间件链。推荐配合 FiberErrorHandler() 一起使用。

func FiberWriteError

func FiberWriteError(c fiber.Ctx, err *exception.ApiException) error

FiberWriteError 错误响应(Fiber v3)

func FiberWriteErrorFromError

func FiberWriteErrorFromError(c fiber.Ctx, err error) error

FiberWriteErrorFromError 兼容任意 error

func FiberWriteJSON

func FiberWriteJSON(c fiber.Ctx, data interface{}) error

FiberWriteJSON 成功响应(Fiber v3)

使用示例:

app.Get("/ping", func(c fiber.Ctx) error {
    return httpx.FiberWriteJSON(c, fiber.Map{"msg": "pong"})
})

func FiberWriteJSONStatus

func FiberWriteJSONStatus(c fiber.Ctx, status int, data interface{}) error

FiberWriteJSONStatus 自定义状态码的成功响应

func FromError

func FromError(err error) *exception.ApiException

FromError 将任意 error 转换为 *ApiException 非 ApiException 时统一视为内部错误;对标准库可识别的错误(如请求体超限)映射为对应业务码。

func GinMethodNotAllowedHandler

func GinMethodNotAllowedHandler() gin.HandlerFunc

GinMethodNotAllowedHandler 返回 Gin 的 405 兜底 Handler

⚠️ 必须搭配 engine.HandleMethodNotAllowed = true 使用!

Gin 默认 HandleMethodNotAllowed = false,此时即便路径已注册但方法不匹配,
也会直接走 NoRoute(即 404),不会进入 NoMethod(405)分支。
如果只注册本 Handler 而未打开开关,405 场景将全部被 404 吃掉。

手动装配示例:

r := gin.New()
r.HandleMethodNotAllowed = true // 👈 关键开关,不要漏
r.NoMethod(httpx.GinMethodNotAllowedHandler())

推荐直接用一键装配:httpx.UseGinNotFound(r)

func GinMiddleware

func GinMiddleware(reporter ...PanicReporter) gin.HandlerFunc

GinMiddleware 统一处理 gin 中的 panic 和错误输出

使用方式:

r := gin.New()
r.Use(httpx.GinMiddleware())

handler 中如果返回错误,可通过 c.Error(err) 上报,或直接 panic 交给中间件处理。

可选参数 reporter:panic 恢复时回调(用于记日志);未传或传 nil 时静默不记。 为向后兼容采用可变参数,仅取第一个非 nil 的 reporter。

func GinNotFoundHandler

func GinNotFoundHandler() gin.HandlerFunc

GinNotFoundHandler 返回 Gin 的 404 兜底 Handler

使用:

r.NoRoute(httpx.GinNotFoundHandler())

响应形如:

{"code":404,"message":"资源未找到: route not found: GET /xxx",
 "request_id":"...","server_time":1714982400}

func GinWriteError

func GinWriteError(c *gin.Context, err *exception.ApiException)

GinWriteError 错误响应(Gin)

func GinWriteErrorFromError

func GinWriteErrorFromError(c *gin.Context, err error)

GinWriteErrorFromError 兼容任意 error

func GinWriteJSON

func GinWriteJSON(c *gin.Context, data interface{})

GinWriteJSON 成功响应(Gin)

使用示例:

r.GET("/ping", func(c *gin.Context) {
    httpx.GinWriteJSON(c, gin.H{"msg": "pong"})
})

func GinWriteJSONStatus

func GinWriteJSONStatus(c *gin.Context, status int, data interface{})

GinWriteJSONStatus 自定义状态码的成功响应

func HTTPMethodNotAllowedHandler

func HTTPMethodNotAllowedHandler() http.Handler

HTTPMethodNotAllowedHandler 返回 net/http 的 405 兜底 Handler,仅供用户手动组装时使用。 通常你不需要直接调用它——直接用 HTTPWithNotFound 包裹 ServeMux 即可自动覆盖 404/405。

func HTTPMiddleware

func HTTPMiddleware() func(http.Handler) http.Handler

HTTPMiddleware 返回 net/http 的 panic 恢复中间件

使用示例:

handler := httpx.HTTPMiddleware()(myHandler)
http.ListenAndServe(":8080", handler)

func HTTPNotFoundHandler

func HTTPNotFoundHandler() http.Handler

HTTPNotFoundHandler 返回 net/http 的 404 兜底 Handler

通常配合自定义 ServeMux 使用,或作为 http.DefaultServeMux 的替代。

func HTTPWithNotFound

func HTTPWithNotFound(next http.Handler) http.Handler

HTTPWithNotFound 包装已存在的 http.Handler(通常是 *http.ServeMux), 同时拦截下游写出的 **404** 与 **405** 响应,改由本包统一兜底输出。

背景:Go 1.22+ 的 http.ServeMux 会区分 404(路径未注册)和 405(路径注册了但方法不匹配), 两种错误都会直接输出“NotFound / Method Not Allowed”纯文本,不符合统一协议。

原理:对下游 ResponseWriter 做一层拦截,当 handler 调用 WriteHeader(404) 或 WriteHeader(405) 时不转发到底层,由外层按统一协议重新输出。405 时会保留下游已写入的 `Allow` 响应头。

使用:

mux := http.NewServeMux()
mux.HandleFunc("GET /hello", helloHandler)
http.ListenAndServe(":8080", httpx.HTTPWithNotFound(mux))

func RestfulFilter

func RestfulFilter() restful.FilterFunction

RestfulFilter 统一处理 go-restful 中的 panic

使用方式:

wsContainer := restful.NewContainer()
wsContainer.Filter(httpx.RestfulFilter())

func RestfulServiceErrorHandler

func RestfulServiceErrorHandler() restful.ServiceErrorHandleFunction

RestfulServiceErrorHandler 返回 go-restful Container 级错误处理器

使用:

container := restful.NewContainer()  // ⚠️ 必须用 NewContainer(),见下方说明
container.ServiceErrorHandler(httpx.RestfulServiceErrorHandler())

适用场景:路由匹配失败(404)、Method 不匹配(405)、Accept 不支持(406)等 由 go-restful 框架自身产生的错误,统一走本包响应协议。

⚠️ 关于 restful.DefaultContainer 的 404 拦截问题:

restful.DefaultContainer 内部使用 http.DefaultServeMux。
当请求路径完全未注册时,http.DefaultServeMux 会直接返回 "404 page not found",
根本不会进入 go-restful 的 dispatch 流程,ServiceErrorHandler 永远拦截不到。
(405 能被拦截是因为路径前缀已注册,请求能进入 dispatch,SelectRoute 失败后才触发)

解决方案(二选一):
  1. 【推荐】改用 restful.NewContainer(),它会把 "/" 注册为兜底路由,
     所有请求都先进 dispatch,ServiceErrorHandler 才能正确拦截 404。
  2. 若必须用 DefaultContainer,在最外层套 HTTPWithNotFound 兜底:
     http.ListenAndServe(":8080", httpx.HTTPWithNotFound(restful.DefaultContainer))

func RestfulWriteError

func RestfulWriteError(req *restful.Request, resp *restful.Response, err *exception.ApiException)

RestfulWriteError 错误响应(go-restful v3)

func RestfulWriteErrorFromError

func RestfulWriteErrorFromError(req *restful.Request, resp *restful.Response, err error)

RestfulWriteErrorFromError 兼容任意 error

func RestfulWriteJSON

func RestfulWriteJSON(req *restful.Request, resp *restful.Response, data interface{})

RestfulWriteJSON 成功响应(go-restful v3)

使用示例:

ws.Route(ws.GET("/ping").To(func(req *restful.Request, resp *restful.Response) {
    httpx.RestfulWriteJSON(req, resp, map[string]any{"msg": "pong"})
}))

func RestfulWriteJSONStatus

func RestfulWriteJSONStatus(req *restful.Request, resp *restful.Response, status int, data interface{})

RestfulWriteJSONStatus 自定义状态码的成功响应

func SetErrorSanitizer added in v2.2.32

func SetErrorSanitizer(fn ErrorSanitizer)

SetErrorSanitizer 注册全局错误脱敏钩子。

通常在服务启动阶段调用一次;重复调用以后注册者为准;传 nil 表示清除钩子。

func UseGinNotFound

func UseGinNotFound(engine *gin.Engine)

UseGinNotFound 一键装配 Gin 的 404/405 兜底能力。

内部会完成三件事,消除易错配置:

  1. 打开 engine.HandleMethodNotAllowed = true(Gin 默认为 false, 不开启时 405 会退化为 404)
  2. 注册 NoRoute Handler —— 路径未命中 → 404
  3. 注册 NoMethod Handler —— 路径命中但方法不匹配 → 405

使用(建议放在所有路由注册之后,也可在之前,Gin 内部按请求触发):

r := gin.New()
r.Use(trace.GinMiddleware(nil))
// ... 注册业务路由 ...
httpx.UseGinNotFound(r)

func WriteError

func WriteError(w http.ResponseWriter, r *http.Request, err *exception.ApiException)

WriteError 写出一个 ApiException 错误响应(net/http) 若 err 为 nil,视为 204 No Content

func WriteErrorFromError

func WriteErrorFromError(w http.ResponseWriter, r *http.Request, err error)

WriteErrorFromError 兼容任意 error

func WriteJSON

func WriteJSON(w http.ResponseWriter, r *http.Request, data interface{})

WriteJSON 成功响应(net/http)

使用示例:

func handler(w http.ResponseWriter, r *http.Request) {
    httpx.WriteJSON(w, r, map[string]any{"name": "alice"})
}

func WriteJSONStatus

func WriteJSONStatus(w http.ResponseWriter, r *http.Request, status int, data interface{})

WriteJSONStatus 自定义 HTTP Status 的成功响应

Types

type ErrorSanitizer added in v2.2.32

type ErrorSanitizer func(ctx context.Context, err *exception.ApiException, requestID string) *exception.ApiException

ErrorSanitizer 错误响应脱敏钩子。

  • ctx:当前请求的 context(可从中读取 request_id、业务注入的运行时上下文等; 部分框架兜底路径可能传入 context.Background());
  • err:即将被序列化为统一 Response 的 ApiException(可能携带后端原始错误文本);
  • requestID:本次请求的追踪 ID(可能为空串;与 ctx 中的值同源,保留参数便于 无 ctx 场景使用);
  • 返回值:实际序列化的 ApiException;返回 nil 表示不修改,按原 err 输出。

type PanicReporter added in v2.2.44

type PanicReporter func(ctx context.Context, rec any)

PanicReporter panic 恢复时的日志回调。

  • ctx:请求上下文(可从中取 request_id 等追踪字段);
  • rec:recover() 捕获到的原始 panic 值。

业务侧可在此用自有 logger + runtime/debug.Stack() 记录完整调用栈。 响应体已默认脱敏(不携带 panic 值),排障信息应经由本回调落日志,而非泄漏给客户端。

type Response

type Response struct {
	Code       int         `json:"code"`
	Message    string      `json:"message,omitempty"`
	Data       interface{} `json:"data,omitempty"`
	RequestID  string      `json:"request_id,omitempty"`
	ServerTime int64       `json:"server_time"`
}

Response 统一响应体

ServerTime 为服务端生成该响应时的 Unix 秒级时间戳,便于客户端做时钟校准、 日志对齐或排障时确认响应时刻。之所以叫 ServerTime 而不是 RequestTime: 响应体里的时间字段表达的是"服务端产出响应的时刻",不是"请求发起的时刻", 这也是业内通用命名(淘宝 / 微信 / AWS 等开放平台)。

type TracingRoundTripper

type TracingRoundTripper struct {
	Base http.RoundTripper
	// HeaderMap 将 trace 字段名 → HTTP Header 名
	// 为 nil 时使用默认映射(request_id → X-Request-Id 等)
	HeaderMap map[string]string
}

TracingRoundTripper 把 ctx 中所有追踪字段透传为请求头

func NewTracingRoundTripper

func NewTracingRoundTripper(base http.RoundTripper) *TracingRoundTripper

NewTracingRoundTripper 构造默认的透传 RoundTripper

func (*TracingRoundTripper) RoundTrip

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

RoundTrip 实现 http.RoundTripper

Jump to

Keyboard shortcuts

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