app.static() 仅做前缀字符串替换,不自动查找或容错;请求 /static/css/main.css 对应 ./public/css/main.css,路径必须严格匹配,末尾不能带斜杠,工作目录影响相对路径解析。

直接用 app.Static() 就能映射,但 404 多数不是没写这行,而是路径字符串没对上——它不做自动查找或容错,只做前缀替换。
app.Static() 的路径匹配是字符串替换,不是目录挂载
浏览器请求 /static/css/main.css,app.Static("/static", "./public") 就会去读 ./public/css/main.css(注意:不是 ./public/static/css/main.css)。它把请求路径的前缀 /static 删掉,再拼到本地路径后面。
- 如果文件实际在
./assets/css/main.css,就必须写app.Static("/static", "./assets"),否则一定 404 -
./public末尾不能带斜杠(./public/),某些 Go 版本会 panic - 工作目录决定
./public的起点:用go run main.go启动时,它是终端当前路径下的子目录,不是main.go所在目录 - 想彻底规避歧义?用绝对路径:
filepath.Join(os.Getenv("PWD"), "public")或filepath.Dir(os.Args[0]) + "/../public"
为什么 /favicon.ico 总是 404
浏览器发的是根路径请求 GET /favicon.ico,而 app.Static("/static", "./public") 只响应以 /static 开头的路径,完全不匹配;app.Use(static.New("./public")) 也只匹配 /favicon.ico 这种无前缀路径,但默认不启用目录浏览或索引逻辑,且不处理 MIME 类型。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 最简方案:
app.Static("/favicon.ico", "./public/favicon.ico")—— Fiber 内部会把它转成单文件服务 - 更可控写法:
app.Get("/favicon.ico", func(c *fiber.Ctx) error { data, _ := os.ReadFile("./public/favicon.ico"); return c.Type("image/x-icon").Send(data) }) - 别指望
app.Static("/", "./public") 能兜底:它会拦截所有未匹配<a style="color:#f60; text-decoration:underline;" title="路由" href="https://m.php.cn/zt/18172.html" target="_blank">路由</a>,包括 API 接口
static.New() 必须显式挂载,且顺序和前缀必须严格一致
static.New() 是终结型 handler,一旦命中就返回文件、不走后续中间件。它不自动剥离前缀,也不校验路径遍历,默认行为极简——生产环境必须手动加固。
- 要支持
/assets/logo.png→./public/assets/logo.png,必须写app.Use("/assets", static.New("./public/assets"));写成app.Use(static.New("./public"))就只能响应/favicon.ico这类根路径请求 - 防盗链、日志、路径校验等中间件,必须放在
static.New()之前注册,否则不会执行 - 目录不存在时它不报错,只默默返回 404;上线前务必加
os.Stat()检查 - 默认不防
../../../etc/passwd—— 要启用安全模式,得手动设.EnableDirListing(false).Browse(false),或在前置中间件里拦截含".."的c.Path()
最容易被忽略的是:Fiber 的静态服务完全独立于模板引擎,c.Render() 不会触发任何静态资源加载逻辑;所有 CSS/JS/图片都必须靠 app.Static() 或 static.New() 显式挂载,漏一条路径,前端就少一个文件。










