RRuna

路由上下文

读取请求、响应内容和访问应用能力

route.Context 是 HTTP handler 的请求上下文。它包装了 http.Request、响应写入器、路由参数、配置和请求级 Scope。

每一次 HTTP 请求都会创建一个新的 route.Context。不要把它保存到全局变量里,也不要在请求结束后继续使用。

基础用法

route.Default().Get("/users/{id}", func(ctx *route.Context) error {
    id := ctx.Param[string]("id")
    return ctx.JSON(runa.Map{"id": id})
})

这段代码从路径 /users/{id} 里读取 id,再返回 JSON。

读取请求数据

route.Default().Get("/search/{category}", func(ctx *route.Context) error {
    category := ctx.Param[string]("category")
    keyword := ctx.Query[string]("keyword")
    page := ctx.Query[int]("page", 1)
    userAgent := ctx.Request().UserAgent()

    return ctx.JSON(runa.Map{
        "category": category,
        "keyword": keyword,
        "page": page,
        "ua": userAgent,
    })
})

常用读取方式:

方法 说明
Param[T](name, fallback...) 读取并转换路径参数
Query[T](name, fallback...) 读取并转换查询参数
Header[T](name, fallback...) 读取并转换请求头
Cookie[T](name, fallback...) 读取并转换 Cookie
Form[T](name, fallback...) 读取并转换表单值
Meta[T](key, fallback...) 读取并转换当前路由元数据
Input[T]() 绑定并验证请求输入到 T
Service[T](name...) 读取注入到 route context 的服务
Request() 取得原始 *http.Request
Response() 取得原始 http.ResponseWriter
Context() 取得请求的 context.Context
Body() 读取请求 body,并恢复给后续逻辑继续读取

写出响应

return ctx.Text("ok")
return ctx.HTML("<h1>ok</h1>")
return ctx.JSON(runa.Map{"ok": true})
return ctx.Blob("application/octet-stream", body)

设置状态码:

return ctx.Status(201).JSON(runa.Map{"created": true})

读取配置

route.Default().Get("/config", func(ctx *route.Context) error {
    name := ctx.Config("app").Get[string]("name")
    return ctx.Text(name)
})

ctx.Config("app") 读取的是 config/app.toml 对应的配置作用域。

从 Context 使用能力

能力对象通常通过对应包的 Default() 获取,例如 cache.Default()database.Default()queue.Default()

route.Default().Get("/cache", func(ctx *route.Context) error {
    store := cache.Default().MustOf[string]("default")
    value, ok, err := store.Get(ctx.Context(), "hello")
    if err != nil {
        return err
    }
    if !ok {
        return ctx.Status(404).Text("cache not found")
    }
    return ctx.Text(value)
})

ctx.Context() 是当前请求的标准库 context,适合传给数据库、缓存、队列等能力。

请求级数据

请求级对象适合存放 trace id、当前用户、权限上下文等临时数据。中间件可以先写入,后续 handler 再读取。

如果是跨请求共享的对象,不要放在 route.Context 里,应该放进 DI、缓存、数据库或业务服务。

错误返回

return ctx.Error(404, "user not found")

更复杂的错误建议使用 errs 工具包,统一错误码和参数。

return errs.New("user not found", errs.Code("user.not_found"))

常见错误

把 route.Context 传到后台协程里

请求结束后,route.Context 不应该继续使用。如果确实要异步处理,请把必要的数据拷贝出来,再交给队列或后台任务。

忘记用 ctx.Context()

调用数据库、缓存、HTTP 客户端时,优先传 ctx.Context(),这样请求取消时,下游操作也能尽快停止。

编辑此页