不能直接用 http.FileServer("./static"),因工作目录不确定导致路径失效、缺乏路径遍历防护、缺失 Content-Type 与缓存头;embed.FS 需 //go:embed 声明、路径相对当前文件、且必须经 http.FS() 转换才能传入 http.FileServer。

为什么不能直接用 http.FileServer("./static")
因为运行时工作目录不等于项目根目录,./static 很可能根本不存在;旧版 Go 对路径遍历防护不严,/static/../../etc/passwd 这类请求可能绕过校验;它还不会自动设置 Content-Type 或缓存头,比如 .js 文件返回 text/plain 就直接被浏览器拒执行。
embed.FS 是生产环境首选,但要注意三点
第一,//go:embed 前不能有空格,且必须紧贴变量声明行;第二,路径是相对于当前 .go 文件的,不能写 ../static,也不能用变量拼接;第三,嵌入后文件名是相对路径(如 static/css/app.css),必须用 http.FS() 包一层才能传给 http.FileServer。
常见写法:
package main
<p>import (
"embed"
"net/http"
)</p><p>//go:embed static/*
var staticFiles embed.FS</p><p>func main() {
fs := http.FS(staticFiles)
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(fs)))
http.ListenAndServe(":8080", nil)
}开发期和生产期怎么切换资源加载方式
硬编码两种逻辑会增加维护成本。推荐用环境变量或构建 tag 控制:
立即学习“go语言免费学习笔记(深入)”;
- 开发时:用
http.Dir("static"),支持热更新,不用每次改 CSS 都重编译 - 生产时:用
embed.FS,打包进二进制,避免部署遗漏文件或路径错乱 - 若需 CMS 上传图片等动态资源,保留外部目录,但必须用
filepath.Clean()和strings.HasPrefix()校验路径,防止遍历攻击
静态资源路径在 HTML 模板里怎么写才不踩坑
绝对路径是底线:/static/logo.png,不是 ./static/logo.png 或 static/logo.png;如果用了构建哈希(如 app.a1b2c3.js),就别手写路径,改用模板变量注入,比如 {{.JSPath}},由 Go 后端根据文件内容生成哈希并渲染。
容易忽略的是:内联关键 CSS 时,embed.FS 读出来的 []byte 要手动转 string 再塞进 <style>,而 JS 如果延迟加载,得确保 /static/ 前缀和 http.StripPrefix 的前缀完全一致,否则 404。


















