Files
blog-server/internal/router/router.go
2026-08-19 22:05:49 +08:00

140 lines
3.0 KiB
Go

package router
import (
"net/http"
"os"
"path/filepath"
"server/internal/config"
"server/internal/middleware"
"server/internal/pkg/httputil"
"github.com/go-chi/chi/v5"
"go.uber.org/fx"
)
type Group string
const (
AdminPublicRoutes Group = "admin_public_routes"
AdminRoutes Group = "admin_routes"
SiteRoutes Group = "site_routes"
)
type Registrar interface {
Register(r chi.Router)
}
type Params struct {
fx.In
JWT *middleware.JWTMiddleware
Auth *middleware.AuthMiddleware
Logger *middleware.LoggerMiddleware
AccessLog *middleware.AccessLogMiddleware
RequestContext *middleware.RequestContextMiddleware
Config *config.Config
AdminPublicRoutes []Registrar `group:"admin_public_routes"`
AdminRoutes []Registrar `group:"admin_routes"`
SiteRoutes []Registrar `group:"site_routes"`
}
func NewRouter(p Params, cfg *config.Config) *chi.Mux {
mux := chi.NewRouter()
// 中间件顺序很重要 洋葱模型 越靠前的中间件 包裹范围越大
// 请求进入:
//
//A 前置代码
// |
// B 前置代码
// |
// C 前置代码
// |
// Handler
// C 后置代码
// B 后置代码
//A 后置代码
//
//响应返回:
mux.Use(
p.RequestContext.Middleware,
p.Logger.Middleware,
p.AccessLog.Middleware,
)
if config.IsDev() {
// 开放静态目录
registerStaticFiles(mux, cfg.File.UploadDir)
// 开发阶段:遍历所有已注册路由的清单接口(无鉴权)
mux.Get("/api/admin/routes", ListRoutes(mux))
}
mux.Route("/api/admin", func(r chi.Router) {
// 免鉴权接口
for _, route := range p.AdminPublicRoutes {
route.Register(r)
}
r.Group(func(r chi.Router) {
// jwt 和 auth中间件
r.Use(p.JWT.Middleware)
r.Use(p.Auth.Middleware(mux))
// 循环挂载所有后台业务模块
for _, route := range p.AdminRoutes {
route.Register(r)
}
})
})
mux.Route("/api", func(r chi.Router) {
for _, route := range p.SiteRoutes {
route.Register(r)
}
})
return mux
}
func registerStaticFiles(r chi.Router, uploadDir string) {
rootDir, _ := os.Getwd()
uploadsDir := filepath.Join(rootDir, uploadDir)
r.Handle("/static/*", http.StripPrefix("/static/", http.FileServer(http.Dir(uploadsDir))))
}
// RouteInfo 路由信息
type RouteInfo struct {
Method string `json:"method"`
Path string `json:"path"`
}
// ListRoutes 遍历所有已注册的路由
func ListRoutes(mux *chi.Mux) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var routes []RouteInfo
err := chi.Walk(mux, func(method string, route string, _ http.Handler, _ ...func(http.Handler) http.Handler) error {
routes = append(routes, RouteInfo{Method: method, Path: route})
return nil
})
if err != nil {
httputil.Fail(w, err)
return
}
httputil.Ok(w, routes)
}
}
func AsRegistrar(group Group, f any) any {
return fx.Annotate(
f,
fx.As(new(Registrar)),
fx.ResultTags(`group:"`+string(group)+`"`),
)
}