refactor: Go 端收缩,移除 SPA 服务与 embed_static

- 删除 embed_static(内嵌 SPA 静态资源)与 handler/ssr_home.go、ssr_icons.go
- router 移除前端页面服务,NoRoute 统一返回 404 JSON
- seo.go 仅保留 robots.txt / sitemap.xml / favicon.ico
- 数据聚合逻辑迁移到 handler/home_boot.go(/api/home-boot)
- 启动日志改为提示前端由 Node 渲染服务器提供
This commit is contained in:
2026-09-09 02:41:53 +08:00
parent 1ce0f123fa
commit ba39376a0e
7 changed files with 19 additions and 2286 deletions

View File

@@ -1,14 +1,12 @@
package router
import (
"encoding/json"
"fmt"
"net/http"
"os"
"path/filepath"
"git.iioio.com/freefire/jiang13-forum/config"
"git.iioio.com/freefire/jiang13-forum/embed_static"
"git.iioio.com/freefire/jiang13-forum/handler"
"git.iioio.com/freefire/jiang13-forum/middleware"
"git.iioio.com/freefire/jiang13-forum/service"
@@ -31,13 +29,9 @@ func Setup(cfg *config.Config) (*gin.Engine, error) {
monitorSvc.StartBackground()
r.Use(middleware.AccessLogMiddleware(monitorSvc))
// dev 模式:跳过内嵌静态资源,前端由 Vite 开发服务器(:5173)提供
// 用户应访问 5173 端口,Vite 通过 proxy 将 /api 等请求转发到本服务(:3000)
if !cfg.DevMode {
if err := embed_static.SetupEmbed(r); err != nil {
return nil, err
}
} else {
// 前端由 Node 渲染服务器提供(对外 :3000),本服务仅提供 API;
// dev 模式前端由 Vite 开发服务器(:5173)提供,/api 经 Vite proxy 转发到本服务
if cfg.DevMode {
fmt.Fprintf(os.Stderr, "[dev] 后端仅提供 API,前端请访问 http://localhost:5173\n")
}
@@ -46,20 +40,6 @@ func Setup(cfg *config.Config) (*gin.Engine, error) {
if cfg.CommunityHub {
fmt.Fprintf(os.Stderr, "[community] 社区枢纽已开启(运维配置),可接收自愿上报\n")
}
// SPA 入口 HTML 注入标题与品牌 JSON,避免刷新时先闪默认文案
embed_static.SetSPADocumentTitle(func() string {
return settingsSvc.SiteBranding().DocumentTitle()
})
embed_static.SetSPABrandingJSON(func() []byte {
b, err := json.Marshal(settingsSvc.SiteBranding())
if err != nil {
return nil
}
return b
})
embed_static.SetSPAFaviconURL(func() string {
return settingsSvc.SiteBranding().Favicon
})
authSvc := service.NewAuthService(cfg.JWTSecret, filter, settingsSvc)
userSvc := service.NewUserService(filter, settingsSvc)
boardSvc := service.NewBoardService()
@@ -138,6 +118,8 @@ func Setup(cfg *config.Config) (*gin.Engine, error) {
pubAPI.GET("/me", h.APIMe)
pubAPI.GET("/boards", h.APIBoards)
pubAPI.GET("/stats", h.APIStats)
// SSR 聚合数据(Vike +data 使用,Node 内部调用)
pubAPI.GET("/home-boot", h.APIHomeBoot)
pubAPI.POST("/community/heartbeat", middleware.RateLimitMiddleware(limiter, "community_heartbeat"), h.APICommunityHeartbeat)
pubAPI.GET("/community/showcase", h.APICommunityShowcase)
pubAPI.POST("/monitor/pageview", middleware.RateLimitMiddleware(limiter, "monitor_pageview"), h.APIMonitorPageview)
@@ -300,48 +282,17 @@ func Setup(cfg *config.Config) (*gin.Engine, error) {
adminAPI.GET("/backup/download/:name", h.APIAdminDownloadBackup)
}
// 后台管理页面由 React SPA 渲染(JSON API 见上方 /api/admin)
// dev 模式下前端由 Vite 提供,后台页面路由不在此注册
if !cfg.DevMode {
admin := r.Group("/admin")
{
admin.GET("/login", func(c *gin.Context) {
c.Redirect(http.StatusFound, "/login")
})
adminAuth := admin.Group("/", authMW.RequireAuth(), authMW.RequireAdmin())
{
adminAuth.GET("/", func(c *gin.Context) { c.Redirect(http.StatusFound, "/admin/dashboard") })
for _, page := range []string{
"dashboard", "boards", "pages", "links", "community", "posts",
"comments", "reports", "users", "badges", "media", "monitor", "settings",
} {
adminAuth.GET("/"+page, embed_static.ServeSPANoIndex)
}
}
}
}
// React SPA 入口
// dev 模式:前端由 Vite(:5173) 提供,非 API 请求返回开发提示
// 生产模式:注入 SEO meta / JSON-LD / 预渲染摘要
if cfg.DevMode {
r.NoRoute(func(c *gin.Context) {
// 非 API 路径由 Node 渲染服务器(生产)或 Vite 开发服务器(dev)处理,
// 本服务不再服务前端页面,未知路径一律 404 JSON
r.NoRoute(func(c *gin.Context) {
if cfg.DevMode {
c.JSON(http.StatusNotFound, gin.H{
"error": "dev 模式下前端由 Vite 提供,请访问 http://localhost:5173",
})
})
} else {
// 文档请求也解析登录 cookie,首页 SSR 才能输出头像/签到/收藏等完整壳
r.GET("/", authMW.OptionalAuth(), h.ServePublicSPA)
r.NoRoute(authMW.OptionalAuth(), func(c *gin.Context) {
if embed_static.IsSPARoute(c.Request.URL.Path) {
h.ServePublicSPA(c)
return
}
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
})
}
return
}
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
})
return r, nil
}