noroute必须在所有get/post等路由注册之后调用,因其仅匹配前面所有路由均未命中的请求;若提前注册,则后续路由永不执行。

必须把 NoRoute 放在所有路由注册之后
否则后续的 r.GET、r.POST 都不会生效。Gin 的 NoRoute 是兜底逻辑,只对「前面所有路由都未匹配」的请求触发。常见错误是把它写在 r.GET("/users", ...) 之前,结果所有请求全被截住,业务路由永远收不到。
- 正确顺序:先注册全部业务路由(包括
r.Group内的),最后调用r.NoRoute(...) - 如果用了
r.Group("/api"),也要等整个分组注册完再挂NoRoute -
NoRoute不受中间件影响——它只看路由树是否匹配,不关心中间件有没有 panic
返回 JSON 还是 HTML?得显式终止响应
只写 c.JSON(404, ...) 不够,必须加 c.Abort() 或直接用 c.AbortWithStatusJSON(),否则 Gin 可能继续往下走,导致 header 重复写入或日志中间件二次执行。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 推荐写法:
c.AbortWithStatusJSON(404, gin.H{"code": "ROUTE_NOT_FOUND", "path": c.Request.URL.Path}) - 若要返回 HTML 页面,需提前调用
r.LoadHTMLGlob("templates/**/*.html"),再在NoRoute中调用c.HTML(404, "errors/404.html", gin.H{"title": "Not Found"}) - 避免只写
c.Status(404)而不输出 body,客户端会收到空响应
区分 API 和前端页面路径,按前缀做分支处理
很多项目同时暴露 /api/v1/... 接口和 /、/app/* 前端路由。未命中时不该统一返回 JSON,而应按路径意图分别响应。
- 示例判断:
if strings.HasPrefix(c.Request.URL.Path, "/api/")→ 返回 JSON 错误 - 否则 →
c.Redirect(302, "/")或c.HTML(404, "spa.html", nil)(适配 Vue/React History 模式) - 注意:不要在
NoRoute里做重定向后还调用c.Abort(),c.Redirect内部已处理
NoRoute 不处理方法不匹配,NoMethod 得单独配
NoRoute 只捕获「路径 + 方法」双重不匹配,比如对 /users 发起 DELETE 请求但没定义该方法,它不会触发。这种属于 405 Method Not Allowed,得靠 r.NoMethod() 单独处理。
- 典型场景:API 客户端误用
PUT访问只支持POST的接口 - 建议一起配置:
r.NoMethod(func(c *gin.Context) { c.AbortWithStatusJSON(405, gin.H{"error": "method not allowed"}) }) -
NoMethod同样必须放在所有路由注册之后,且与NoRoute无执行顺序依赖
NoMethod,以及忘记在 NoRoute 里调用 Abort 类方法——这两处一错,404 就会表现得不稳定或响应头异常。










