http.FileServer需配合http.Handle和http.ListenAndServe使用,根目录须用绝对路径避免404;挂载子路径需用http.StripPrefix("/prefix/", fs)并确保末尾带/;默认无缓存头,需手动设置;生产环境必须禁用目录列表以防泄露结构。

用 http.FileServer 启动服务,但根目录不能写错
Go 的静态文件服务器核心就是 http.FileServer,它本身不启动 HTTP 服务,只负责“怎么读文件、怎么响应”,必须配合 http.Handle 和 http.ListenAndServe 才能跑起来。
常见错误是把路径传成相对路径却没注意工作目录——比如代码里写 http.Dir("static"),但你用 go run cmd/server.go 运行时,当前工作目录是 cmd/,结果就找不到 static/ 目录,访问直接 404。
- 推荐统一用绝对路径:
http.Dir(filepath.Join(os.Getenv("PWD"), "static"))或更稳妥地用filepath.Abs("static") - 开发期可加一行日志确认:
log.Printf("serving from: %s", absPath) - 别依赖
.或空字符串作为根目录,尤其上线后工作目录不可控
http.StripPrefix 不只是“去掉前缀”,它决定文件查找路径
挂载静态资源到 /assets/ 而不是根路径时,http.StripPrefix("/assets/", fileServer) 是必需的。它的作用不是“美化 URL”,而是把请求路径 /assets/css/main.css 转成 /css/main.css,再交给 fileServer 去磁盘上找 ./static/css/main.css。
漏掉这一步,fileServer 就会试图打开 ./static/assets/css/main.css,自然报 404。
- 顺序不能反:必须先
StripPrefix,再传给FileServer;反过来写(比如FileServer(Dir("static")).ServeHTTP手动调)会绕过安全检查 - 前缀末尾要带
/:"/assets/"✅,"/assets"❌(否则/assets123也会被 strip) - 多个静态目录需分别处理,不能共用一个
FileServer实例
默认行为不设缓存头,前端反复拉资源
http.FileServer 默认返回的响应里没有 Cache-Control 或 ETag,浏览器每次刷新都重新下载 JS/CSS,既慢又浪费带宽。
这不是 bug,是设计:Go 标准库故意保持中立,把缓存策略留给业务决定。但实际项目里几乎都需要配。
- 最简方案:包一层 handler,写死头:
w.Header().Set("Cache-Control", "public, max-age=31536000")(一年,适合带哈希的构建产物) - 区分类型更合理:HTML 设
no-cache,JS/CSS 设长缓存,图片按需设 - 别用
http.ServeContent手动实现——它虽支持If-None-Match,但需要自己算modtime和size,易出错
上线前必须关掉目录列表,否则泄露结构
默认情况下,如果请求的是一个目录(如 /static/)且该目录下没有 index.html,http.FileServer 会自动生成一个 HTML 列表,把所有子文件名列出来。开发时方便,生产环境等于把项目结构白送出去。
这个行为无法用参数关闭,只能靠“让它找不到目录”来规避。
- 确保每个公开路径下都有
index.html(哪怕空文件),或用http.NotFoundHandler()拦截目录请求 - 更彻底的做法:用自定义
http.FileSystem实现,重写Open方法,在os.IsDir(err)时直接返回os.ErrNotExist - 别指望前端路由(如 Vue Router 的 history 模式)自动 fallback——它只管 JS 层,404 仍由 Go 返回,目录列表照常出现
路径遍历防护是内置的,但目录列表不是安全漏洞,是功能开关——没人关,它就开着。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











