go项目路由混乱的本质是职责未分离,应按业务域(如user、order)拆分路由文件,统一在internal/routing/router.go中通过setup(e *echo.echo)注册;main.go仅初始化配置、构建实例、调用setup并启动;路由文件只挂载handler,不初始化依赖或配置,中间件须绑定到对应group而非全局。

路由文件混乱,本质是职责没拆开、路径没分层、注册逻辑混在启动代码里。直接把所有 GET POST 塞进 main.go 或一个 routes.go,不出三个月就没人敢改路由了。
按业务域拆分路由文件,别按 HTTP 方法
把所有 GET 放一起、所有 POST 放一起,看似“归类”,实则割裂业务语义。用户管理相关接口(/users、/users/{id}/roles)硬生生被拆到四个文件里,查个完整流程得切五次。
- 每个业务模块建独立文件,比如
user_routes.go、order_routes.go,文件内只处理该域的全部动词 - 用
e.Group("/api/v1")统一封装前缀,避免每个 handler 都写重复路径 - Group 可嵌套:先
users := api.Group("/users"),再users.Group("/{id}").GET("/roles", ...),保持层级可读 - 别在路由文件里写 handler 实现——只负责挂载,handler 函数定义放到
handlers/下对应子目录
路由注册入口必须唯一且显式
如果项目里有 RegisterRoutes(e *echo.Echo)、SetupAPI(e)、initRouters() 三个函数,还分别被 main.go、server.go、cmd/start.go 调用,那路由就注定失控。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 只保留一个注册入口,约定放在
internal/routing/router.go,函数名统一为Setup(e *echo.Echo) -
main.go只做三件事:初始化配置 → 初始化 Echo 实例 → 调用routing.Setup(e)→ 启动服务器 - 所有路由文件通过 init() 注册到全局路由表?禁止。init() 不可控、难测试、依赖顺序易错
- 需要条件注册(如调试模式加 /debug/*)?用参数控制
Setup(e, WithDebug(true)),别绕开主入口
中间件绑定要跟路由组强绑定,别全局堆砌
看到 e.Use(auth.Middleware(), logger.Middleware(), cors.Middleware()) 写在最顶上,就知道这个项目迟早要为某个不需要鉴权的健康检查接口头疼。
- 登录、用户资料等敏感路由组,才用
auth.Group(...);公开 API(如 /status、/metrics)走无中间件的裸 Group - JWT 验证中间件如果对
/api/v1/public/*也生效,就会导致 OPTIONS 预检失败——因为没带 token,但预检不该验证 - 用
e.Group("/api/v1").Use(jwt.Middleware()),而不是e.Use(jwt.Middleware()),避免误伤 - 中间件本身要支持 SkipFunc,比如
jwt.New(...).Skipper = func(c echo.Context) bool { return c.Path() == "/api/v1/status" }
别让路由文件承担配置解析或 DB 初始化职责
在 user_routes.go 里看到 db := config.GetDB() 或 viper.GetString("redis.addr"),说明路由已越界。它只该知道“谁来处理 /users”,不该管“DB 怎么连”。
- handler 函数签名统一为
func(c echo.Context) error,所需依赖(DB、cache、mailer)通过依赖注入传入,比如用user.NewHandler(userRepo, mailer) - 路由文件里只出现
users.GET("", h.List)这种纯粹挂载,不 new、不 init、不 config.Load - 如果 handler 需要动态配置(如限流阈值),把配置结构体作为字段注入 handler 实例,而不是在
h.List里实时读 viper - 测试时能直接 new handler 并传 mock 依赖——这是判断职责是否干净的黄金标准
最难的不是拆文件,而是让所有人遵守“路由只注册、不初始化、不决策”的边界。一旦 handler 开始调 viper.Get 或 sql.Open,目录再整齐也是假象。










