handler

package
v0.6.1 Latest Latest
Warning

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

Go to latest
Published: Aug 8, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package handler 提供声明式 HTTP handler 包装器:把 auth 策略 + 资源注入 + 错误归一化从业务 handler 上移到包装器,handler 只关心 (ctx, req) => (resp, error)。

声明式声明"这个 handler 需要什么"(认证策略、依赖),由包装器统一注入, 业务函数保持纯净——只接收 ctx 和解析好的请求,返回响应或 error。

这其实是 pkg/callbacks + pkg/middleware/auth + pkg/afterwork + DI 组合成一个 ergonomic 的 handler 装饰器:

  • WithAuth(policy):在调业务函数前做认证/授权,User 注入 ctx;
  • WithInject(deps):把任意依赖(DB、cache、client...)装入 ctx 供 handler 取;
  • WithAfterwork:挂上 afterwork.Middleware,handler 里 afterwork.Defer(...) 投递的响应后副作用在响应返回后跑完;
  • WithRatelimit:声明式限流;
  • WithMiddleware:挂任意标准中间件(func(http.Handler) http.Handler)于最外层—— 核心不依赖 contrib,故可即插即用如 contrib/wasm 的过滤器等;
  • 返回的 error 自动经 errors.WriteHTTP 归一化为统一错误响应。

用法:

type CreateOrderReq struct { UserID string; Sku string }
type CreateOrderResp struct { OrderID string }

h := handler.New[CreateOrderReq, CreateOrderResp](
    "POST /orders",
    func(ctx context.Context, req *CreateOrderReq) (*CreateOrderResp, error) {
        user := auth.GetUserFromContext(ctx)      // 认证后注入
        db := handler.MustGet[*sql.DB](ctx, "db") // 依赖注入
        id, err := createOrder(ctx, db, user.ID(), req.Sku)
        if err != nil { return nil, err }
        afterwork.Defer(ctx, func(c context.Context) { // 响应后副作用
            _ = webhook.Notify(c, orderEvent{id})
        })
        return &CreateOrderResp{OrderID: id}, nil
    },
    handler.WithAuth(authPolicy),
    handler.WithInject("db", orderDB),
    handler.WithAfterwork(),
)
mux.Handle("/orders", h)

泛型参数 I 是请求体类型(指针),O 是响应体类型(指针),均通过 JSON 编解码。 请求方法固定为方法字段(Method);query/path 参数由调用方自行从 *http.Request 取(本包装器只管 body + auth + error + 响应后副作用)。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Get

func Get[T any](ctx context.Context, name string) (T, bool)

Get 从 ctx 取出命名依赖并断言为 *T。不存在或类型不符返回 nil,false。 业务函数中典型用法:db := handler.MustGet[*sql.DB](ctx, "db")。

func MustGet

func MustGet[T any](ctx context.Context, name string) T

MustGet 同 Get,但类型不符/不存在时 panic(用于启动期配置错误,早炸)。

Types

type AuthPolicy

type AuthPolicy func(ctx context.Context, r *http.Request) (auth.User, error)

AuthPolicy 声明式认证策略:由调用方实现,返回认证后的 User 或 error。 通常包装 pkg/middleware/auth.Authenticator.Authenticate + Authorizer.Authorize。 返回的 User 会被注入 ctx(供业务函数用 auth.GetUserFromContext 取出)。 resource/action 用于授权检查;返回 nil User 表示匿名访问(允许则放行)。

type Func

type Func[I any, O any] func(ctx context.Context, req *I) (*O, error)

Func 业务 handler 函数签名:接收 ctx 和解析好的请求体,返回响应体或 error。 ctx 已注入认证后的 User(若有 WithAuth)和声明式依赖(若有 WithInject)。

type Handler

type Handler[I any, O any] struct {
	// contains filtered or unexported fields
}

Handler 包装后的 http.Handler。实现 http.Handler 接口,可直接挂到 mux。

func New

func New[I any, O any](method string, fn Func[I, O], opts ...Option) *Handler[I, O]

New 创建声明式 Handler。method 可为空(不限方法);fn 是业务函数。 opts 依次应用 WithAuth / WithInject / WithAfterwork 等。

func (*Handler[I, O]) ServeHTTP

func (h *Handler[I, O]) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP 实现 http.Handler。 包装顺序(由外到内):WithMiddleware(用户中间件)→ ratelimit → afterwork → handle(auth+inject+body+fn)。 用户中间件最外层(可提前短路);限流次之(超限不解析 body);afterwork 再次(响应后副作用跑完才放行)。

type Option

type Option func(*config)

Option 配置 Handler。

func WithAfterwork

func WithAfterwork(opts ...afterwork.Option) Option

WithAfterwork 挂载 afterwork.Middleware:handler 里 afterwork.Defer(...) 投递的响应后副作用,在响应返回后由中间件等待跑完。opts 透传给 afterwork。

func WithAuth

func WithAuth(p AuthPolicy) Option

WithAuth 附加声明式认证策略。handler 执行前先调 policy: 失败则经 errors.WriteHTTP 返回错误响应;成功则把 User 注入 ctx。

func WithInject

func WithInject(name string, dep any) Option

WithInject 注入一个命名依赖到 ctx,业务函数用 Get[T](ctx, name) 取出。 可多次调用注入多个依赖。

func WithMethod

func WithMethod(m string) Option

WithMethod 设置允许的 HTTP 方法(如 "POST")。空表示不限。

func WithMiddleware added in v0.3.0

func WithMiddleware(mw ...func(http.Handler) http.Handler) Option

WithMiddleware 附加任意标准 HTTP 中间件(func(http.Handler) http.Handler),挂在包装链的 **最外层**——先于 ratelimit/afterwork/auth 执行,可提前短路(拒绝/改写)。多次传入或一次传多个时, **靠前的在更外层**(WithMiddleware(a, b) 中 a 包住 b 包住其余)。

核心不依赖 contrib,故通过这个通用口即插即用任意中间件——例如把 contrib/wasm 的过滤器绑上:

handler.New(method, fn,
    handler.WithMiddleware(wasm.Middleware(mod)), // wasm 沙箱过滤器
    handler.WithRatelimit(lim, keyFn),
)

func WithRatelimit

func WithRatelimit(l ratelimit.Limiter, keyFn ratelimit.KeyFunc) Option

WithRatelimit 附加声明式限流:limiter 按 keyFn 提取的 key 限流, 超限返回 429 + Retry-After。限流在认证前执行(超限连 body 都不解析)。 传 nil limiter 表示不限流。

Jump to

Keyboard shortcuts

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