package admin import ( "embed" "io/fs" "net/http" "strings" "github.com/gin-gonic/gin" ) //go:embed all:dist var distFS embed.FS // Register 把内嵌的后台 SPA 挂到 /admin 下,index.html 做 SPA fallback func Register(r *gin.Engine) { sub, err := fs.Sub(distFS, "dist") if err != nil { panic(err) } fileServer := http.FileServer(http.FS(sub)) handler := func(c *gin.Context) { // 去掉前缀 /admin,交给内嵌文件服务器 reqPath := strings.TrimPrefix(c.Request.URL.Path, "/admin") reqPath = strings.TrimPrefix(reqPath, "/") // 若请求的是真实存在的静态资源,直出;否则回退 index.html(前端路由) if reqPath != "" { if f, err := sub.Open(reqPath); err == nil { _ = f.Close() c.Request.URL.Path = "/" + reqPath fileServer.ServeHTTP(c.Writer, c.Request) return } } // SPA fallback data, err := fs.ReadFile(sub, "index.html") if err != nil { c.String(http.StatusInternalServerError, "admin dist missing") return } c.Data(http.StatusOK, "text/html; charset=utf-8", data) } r.GET("/admin", func(c *gin.Context) { c.Redirect(http.StatusFound, "/admin/") }) r.GET("/admin/*filepath", handler) }