gin模板路径需用相对启动目录或绝对路径;表单post需确保content-type且避免重复读body;模板插值禁用safe等绕过转义;static路由须注册在最外层且优先于其他路由。

模板路径不生效:Gin的LoadHTMLGlob必须用相对路径从二进制运行位置算起
Gin 加载 HTML 模板时,LoadHTMLGlob 的路径不是相对于 main.go 文件,而是相对于程序启动时的当前工作目录(os.Getwd())。很多人在 IDE 里直接运行,工作目录是项目根目录,但打包成二进制后,如果在别的路径执行,模板就全 404。
- 统一做法:把模板放在
templates/目录下,并在main()中用router.LoadHTMLGlob("templates/**/*") - 更稳妥的方式是硬编码绝对路径:用
filepath.Join(executableDir, "templates", "**", "*"),其中executableDir通过os.Executable()获取 - 注意 Windows 下路径分隔符问题 ——
filepath.Join自动处理,别手拼"templates\*.html"
表单提交后无法获取POST数据:Gin默认不自动解析application/x-www-form-urlencoded
Gin 的 c.PostForm("field") 看似能取值,但前提是请求头 Content-Type 是 application/x-www-form-urlencoded,且你没手动调用 c.ShouldBind() 或启用中间件。否则 PostForm 返回空字符串,也不报错,容易误判为前端没传。
- 确保 HTML 表单有
method="POST"和enctype="application/x-www-form-urlencoded"(这是默认值,可省略) - 后端无需额外配置,但要检查是否误加了
c.Request.Body的手动读取 —— 读一次后流就耗尽,PostForm再调用会失败 - 调试时打印
c.Request.Header.Get("Content-Type")和c.Request.ContentLength,确认请求确实发出了数据
模板中显示用户输入内容时未转义:XSS风险藏在{{.Content}}里
Gin 默认使用 Go 标准库 html/template,它会对 {{.XXX}} 插值自动 HTML 转义 —— 这是好事。但如果你用了 {{.Content | safe}}、{{.Content | html}} 或 {{.Content | printf "%s"}},就绕过了转义,用户提交 <script>alert(1)</script> 就直接执行。
- 除非你明确信任该字段(比如后台管理员编辑的富文本),否则一律用原生
{{.Content}} - 需要保留简单格式(如换行、粗体)?用服务端预处理:把
替换成<br>,把**bold**渲染成<strong>bold</strong>,再交给模板 —— 不要在模板里用safe - 如果用了第三方模板函数(比如自定义
markdownfilter),确认它返回的是template.HTML类型且内容已净化
路由嵌套与静态资源冲突:router.Static("/static", "./static") 必须在LoadHTMLGlob之后
Gin 的 Static 中间件会拦截所有匹配路径的请求。如果你先注册了 router.Static("/static", ...),再调用 LoadHTMLGlob,看似没问题;但一旦你加了 router.Group("/forum") 并在组内注册 GET "/",而用户访问 /forum/static/css/app.css,就会命中 group 路由而非静态文件中间件 —— 因为 Gin 匹配顺序是“先注册的中间件先执行”,但路由树匹配优先级高于中间件顺序。
- 静态资源路由必须注册在最外层
router上,且最好放在所有GET/POST路由之前 - 不要把静态资源挂到子 group 下(比如
forumGroup.Static("/static", ...)),那会导致路径变成/forum/static/...,而 HTML 中引用仍是/static/... - 开发时可用
router.StaticFS("/static", http.Dir("./static")),生产建议用 Nginx 托管静态资源
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











