140 lines
3.0 KiB
Go
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)+`"`),
|
|
)
|
|
}
|