Files
sundynix-site/server/internal/router/router.go
T
Blizzard 0250355dcd feat: RSS 订阅源 + 仓库 README
- GET /rss.xml 输出 RSS 2.0(已发布文章,SUNDYNIX_SITE_URL 可配)
- vite 代理补 /rss.xml,页脚 RSS 链接生效
- README:结构、开发流程、环境变量、后端规范、API 速览

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 11:06:21 +08:00

90 lines
2.4 KiB
Go

package router
import (
"io/fs"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"git.sundynix.cn/Blizzard/sundynix-site/server/internal/handler"
"git.sundynix.cn/Blizzard/sundynix-site/server/internal/middleware"
"git.sundynix.cn/Blizzard/sundynix-site/server/internal/pkg/resp"
"git.sundynix.cn/Blizzard/sundynix-site/server/internal/webfs"
)
func New(db *gorm.DB) (*gin.Engine, error) {
r := gin.New()
r.Use(gin.Logger(), gin.Recovery(), middleware.CORS())
// ── 公开 API ──
api := r.Group("/api")
{
api.GET("/healthz", func(c *gin.Context) {
resp.OK(c, gin.H{"status": "ok"})
})
posts := handler.NewPostHandler(db)
api.GET("/posts", posts.List)
api.GET("/posts/:slug", posts.Get)
}
// RSS 订阅源(页脚 RSS 链接指向这里)
r.GET("/rss.xml", handler.NewRSSHandler(db).Feed)
// ── 管理端 API ──
adminAuth := handler.NewAdminAuthHandler()
api.POST("/admin/login", adminAuth.Login)
adminAPI := api.Group("/admin", middleware.Auth())
{
posts := handler.NewAdminPostHandler(db)
adminAPI.GET("/posts", posts.List)
adminAPI.POST("/posts", posts.Create)
adminAPI.GET("/posts/:id", posts.Get)
adminAPI.PUT("/posts/:id", posts.Update)
adminAPI.DELETE("/posts/:id", posts.Delete)
}
// ── 静态站点:/admin → 管理端,其余 → 用户端 ──
webDist, err := webfs.WebDist()
if err != nil {
return nil, err
}
adminDist, err := webfs.AdminDist()
if err != nil {
return nil, err
}
webServer := http.FileServer(http.FS(webDist))
adminServer := http.StripPrefix("/admin", http.FileServer(http.FS(adminDist)))
r.NoRoute(func(c *gin.Context) {
path := c.Request.URL.Path
if strings.HasPrefix(path, "/api/") {
resp.NotFound(c, "接口不存在")
return
}
if path == "/admin" || strings.HasPrefix(path, "/admin/") {
serveSPA(c, adminDist, adminServer, strings.TrimPrefix(path, "/admin"), "/admin/")
return
}
serveSPA(c, webDist, webServer, path, "/")
})
return r, nil
}
// serveSPA 真实文件直接吐,否则回退 index.html 交给前端路由。
func serveSPA(c *gin.Context, dist fs.FS, server http.Handler, rel, fallback string) {
p := strings.TrimPrefix(rel, "/")
if p != "" {
if _, err := fs.Stat(dist, p); err == nil {
server.ServeHTTP(c.Writer, c.Request)
return
}
}
c.Request.URL.Path = fallback
server.ServeHTTP(c.Writer, c.Request)
}