必须同时加载模板文件和挂载静态路由:用r.LoadHTMLGlob("templates/*/")递归加载多级模板,用r.Static("/css","templates/css")映射静态资源路径,否则分别报模板未找到或CSS 404错误。

Gin 要正确渲染 HTML 页面并让 CSS/JS 等静态资源可访问,必须同时完成两件事:加载模板文件 + 挂载静态路由。漏掉任一环节,就会出现 template: "index.html" not found 或浏览器控制台报 404 加载 /css/app.css 失败——这不是 Gin “不支持”,而是路径映射没对上。
怎么用 LoadHTMLGlob 加载多级目录下的模板
模板路径在 c.HTML() 中传的是逻辑名(比如 "admin/dashboard.html"),不是磁盘路径;Gin 需要提前把所有可能用到的文件读进内存。用 LoadHTMLGlob 最稳妥:
-
r.LoadHTMLGlob("templates/**/*")能递归加载templates下任意层级的所有文件(含子目录) - 如果只写
"templates/*",它不会进入templates/admin/这类子目录,导致c.HTML(200, "admin/index.html", nil)报错 - 模板文件里用
{{define "admin/index.html"}}显式声明名字,否则 Gin 无法识别嵌套路径下的模板 - 不要在 IDE 内直接运行(如 GoLand 的 ▶️ 按钮),工作目录可能不是项目根目录,建议用终端
go run main.go
为什么 /static 映射不到 asset/css 目录
r.Static("/static", "asset/css") 表示:当浏览器请求 /static/main.css 时,Gin 去找磁盘上的 asset/css/main.css。关键在于两个路径的“前缀”必须严格对应:
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- HTML 中引用必须写
<link rel="stylesheet" href="/static/main.css">,不能写./css/main.css或/css/main.css - 如果想用
/css/main.css这个 URL,就得注册r.Static("/css", "asset/css") -
r.StaticFS和gin-contrib/static是替代方案,但原生r.Static足够轻量且无额外依赖 - 多个静态目录要分别注册,比如
r.Static("/js", "asset/js")和r.Static("/img", "asset/img")
SPA 应用刷新 404 怎么 fallback 到 index.html
前端路由(如 Vue Router 的 history 模式)刷新页面时,浏览器会向后端发真实请求,比如 GET /user/profile。Gin 默认没有这个路由,直接返回 404。解决方法是加一个兜底路由:
- 把它放在所有
GET路由定义之后、r.Run()之前 - 写法:
r.NoRoute(func(c *gin.Context) { c.File("./templates/index.html") }) - 注意:不能用
c.HTML(),因为此时模板引擎已找不到匹配的模板名;c.File()是直接读取磁盘文件返回 - 确保
index.html在磁盘路径正确,且静态资源(CSS/JS)引用路径与r.Static注册的 URL 前缀一致
最容易被忽略的是模板名和磁盘路径的双重脱节:一方面 LoadHTMLGlob 没覆盖子目录导致 c.HTML 找不到模板;另一方面 HTML 里写的 href="/css/style.css" 和 r.Static("/static", "...") 的前缀不一致,导致样式白屏。这两处必须同步对齐,缺一不可。


















