Files
2026-07-09 19:18:04 +08:00

57 lines
1.5 KiB
Go

package api
import (
"io/fs"
"net/http"
"path"
"strings"
"github.com/gin-gonic/gin"
"oci-portal/internal/webui"
)
// registerWebUI 挂载嵌入的前端产物。dev 模式走 vite devServer,不经此路径。
func registerWebUI(r *gin.Engine) error {
sub, err := webui.Dist()
if err != nil {
return err
}
mountSPA(r, sub)
return nil
}
// mountSPA 注册 NoRoute 兜底:命中真实文件直出,API 前缀保持 JSON 404,
// 其余路径回 index.html 交给 SPA 路由。
func mountSPA(r *gin.Engine, sub fs.FS) {
fileServer := http.FileServer(http.FS(sub))
r.NoRoute(func(c *gin.Context) {
p := c.Request.URL.Path
if strings.HasPrefix(p, "/api/") || strings.HasPrefix(p, "/ai/") {
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
return
}
if name := strings.TrimPrefix(path.Clean(p), "/"); name != "" {
if _, err := fs.Stat(sub, name); err == nil {
setStaticCacheHeader(c, p)
fileServer.ServeHTTP(c.Writer, c.Request)
return
}
}
// SPA 路由统一回 index.html,禁缓存保证发版后入口即时更新
c.Header("Cache-Control", "no-cache")
c.Request.URL.Path = "/"
fileServer.ServeHTTP(c.Writer, c.Request)
})
}
// setStaticCacheHeader 按路径设缓存策略:vite 产物带内容 hash,/assets/* 可永久缓存;
// 其余真实文件(favicon 等)不带 hash,禁强缓存。
func setStaticCacheHeader(c *gin.Context, p string) {
if strings.HasPrefix(p, "/assets/") {
c.Header("Cache-Control", "public, max-age=31536000, immutable")
return
}
c.Header("Cache-Control", "no-cache")
}