package httpserver import ( "embed" "encoding/json" "io/fs" "net/http" "os" ) // consoleAssets 将控制台静态资源编译进 Orbit,避免运行容器依赖 Node.js、外部 CDN // 或额外的文件挂载。控制台只调用版本化 HTTP API,不读取数据库。 // //go:embed console var consoleAssets embed.FS // RegisterConsole 注册本地及生产可复用的 Orbit 控制台入口。 // /console 不改变业务 API 的认证和路由;静态页面自身不包含凭据。 func RegisterConsole(server *http.Server) { if server == nil { return } mux, ok := server.Handler.(*http.ServeMux) if !ok { return } assets, err := fs.Sub(consoleAssets, "console") if err != nil { return } files := http.StripPrefix("/console/", http.FileServer(http.FS(assets))) mux.HandleFunc("GET /console", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/console/", http.StatusPermanentRedirect) }) mux.HandleFunc("GET /console/config", func(w http.ResponseWriter, r *http.Request) { // 队列 ID 只是控制台的默认范围,不是凭据。Token 仍由每个授权 API // 自己校验;这里不返回任何秘密,也不访问数据库。 w.Header().Set("Cache-Control", "no-store") w.Header().Set("Content-Type", "application/json") w.Header().Set("X-Content-Type-Options", "nosniff") _ = json.NewEncoder(w).Encode(struct { DefaultQueueID string `json:"default_queue_id"` }{DefaultQueueID: os.Getenv("ORBIT_CONSOLE_QUEUE_ID")}) }) mux.Handle("GET /console/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Cache-Control", "no-store") w.Header().Set("X-Content-Type-Options", "nosniff") files.ServeHTTP(w, r) })) }