package common import ( "net/http" "os" "path/filepath" "strings" "github.com/gogf/gf/v2/net/ghttp" ) // SpaFallback 单页应用 history 路由回退中间件:prefix 路径下请求对应的静态文件不存在 // (即前端路由,如 /admin/orders)时回退 index.html;真实静态文件交给后续静态服务处理。 // root 为前端构建产物目录,prefix 为托管路径前缀(如 "/admin")。 func SpaFallback(root, prefix string) ghttp.HandlerFunc { root = filepath.Clean(root) index := filepath.Join(root, "index.html") return func(r *ghttp.Request) { path := r.URL.Path if r.Method == http.MethodGet && (path == prefix || strings.HasPrefix(path, prefix+"/")) { rel := strings.TrimPrefix(path, prefix) candidate := filepath.Clean(filepath.Join(root, rel)) if !strings.HasPrefix(candidate, root) { r.Middleware.Next() return } if _, err := os.Stat(candidate); err != nil { r.Response.ServeFile(index) return } } r.Middleware.Next() } }