Router Primer
Router Primer
Section titled “Router Primer”当你已经通过 稳定根 确认改动仍属于默认服务路径,而且问题进一步收窄到服务如何将 URL 映射到 handler 时,就打开这一页:哪条路径胜出、如何提取 params、命名路由如何反解。
router 拥有 HTTP route matching、path parameter 提取、route group 与反向路由。它被有意设计得很窄:它不了解 JSON 响应、auth 决策或应用构造。
app.Get("/api/v1/items", http.HandlerFunc(items.List))app.Post("/api/v1/items", http.HandlerFunc(items.Create))
grp := app.Group("/api/v1/users")grp.Get("/:id", http.HandlerFunc(users.Get))什么时候从这里开始
Section titled “什么时候从这里开始”- 你正在添加、删除或重组 URL pattern
- 你正在修改 path parameter 提取或
Param助手 - 你正在用共享前缀或 middleware 构建 route group
- 你正在用
WithRouteName反解命名路由 URL - 你正在用
Static或StaticFS挂载静态文件树
什么时候不该从这里开始
Section titled “什么时候不该从这里开始”- 改动关于响应格式或错误格式化 — 从
contract开始 - 改动引入了 auth 验证或 security headers — 从
security开始 - 工作关于 app 如何组装和启动 — 从
core开始 - 改动添加了 tenant 专属路由工厂、feature-flag routing 或前端缓存策略
当前仓库里先读哪些文件
Section titled “当前仓库里先读哪些文件”router/module.yamlreference/standard-service/internal/app/routes.gorouter/cache.go
更具体的归属例子
Section titled “更具体的归属例子”这些工作适合留在 router | 一旦变成这些问题就应移出 |
|---|---|
NewRouter、AddRoute、Group — 结构化基础元语 | 隐式路由注册、反射驱动的发现,或服务构造 |
从匹配路径中提取 Param | 路由参数验证策略或业务规则守卫 |
WithRouteName 与命名路由 URL 反解 | stdlib-shadow handler 别名或框架式 controller dispatch |
Static / StaticFS — 小型挂载基础元语 | 前端资产策略、SPA fallback、cache headers 或 ETag 生成 |
路由通过 core.App(典型路径)或直接在 router.Router 上注册(需要独立路由器时)。
通过 core.App 注册路由
Section titled “通过 core.App 注册路由”app.Get("/api/users", http.HandlerFunc(handler.ListUsers))app.Post("/api/users", http.HandlerFunc(handler.CreateUser))app.Put("/api/users/:id", http.HandlerFunc(handler.UpdateUser))app.Delete("/api/users/:id", http.HandlerFunc(handler.DeleteUser))读取路径参数
Section titled “读取路径参数”import "github.com/spcent/plumego/router"
func (h UserHandler) Get(w http.ResponseWriter, r *http.Request) { id := router.Param(r, "id") // 从匹配路径中提取 :id}路由分组(共享前缀)
Section titled “路由分组(共享前缀)”import "github.com/spcent/plumego/router"
r := router.NewRouter()
api := r.Group("/api/v1")api.AddRoute("GET", "/users", http.HandlerFunc(handler.ListUsers))api.AddRoute("POST", "/users", http.HandlerFunc(handler.CreateUser))api.AddRoute("GET", "/users/:id", http.HandlerFunc(handler.GetUser))api.AddRoute("DELETE", "/users/:id", http.HandlerFunc(handler.DeleteUser))命名路由与反向解析
Section titled “命名路由与反向解析”import "github.com/spcent/plumego/router"
// 带名称注册app.AddRoute(http.MethodGet, "/api/users/:id", http.HandlerFunc(handler.GetUser), router.WithRouteName("user-detail"))
// 反解 URLurl := app.URL("user-detail", "id", "42") // → "/api/users/42"// 匹配 /files/images/logo.png → filepath = "images/logo.png"app.Get("/files/*filepath", http.HandlerFunc(handler.ServeFile))
func (h FileHandler) Serve(w http.ResponseWriter, r *http.Request) { path := router.Param(r, "filepath")}静态文件服务
Section titled “静态文件服务”r := router.NewRouter()r.Static("/static", "./public") // 从目录提供r.StaticFS("/assets", http.FS(embeddedFS)) // 从 fs.FS 提供为什么单独写这一页
Section titled “为什么单独写这一页”路由注册是服务将处理的每个请求的入口映射。如果路由难以 grep,读者就无法追踪请求路径。router 强制执行注册显式且线性的规则:一个方法、一条路径、一个 handler。一旦路由学会了 feature flag、tenant ID 或 plugin catalog,这一约束就消失了。
- router API 快速参考 — 完整函数签名、路径语法和静态文件服务
- Core Primer
- Contract Primer
- 参考应用
- 仓库边界