Initial commit: 可转债轮动分析系统
- 实时行情:东财push2主源 + 腾讯批量报价备用源(自动切换) - 历史K线:东财push2his主源 + 腾讯web子域备用源(含熔断机制) - 增量同步:支持 -incr/-since 参数按存档日期增量入库 - 策略回测:净值曲线/10指标/基准对比,含基本面过滤 - 用户认证:用户名密码 + 邮箱验证码双登录方式 - 前端:三Tab SPA(实时行情/策略回测/数据管理)
This commit is contained in:
71
internal/router/router.go
Normal file
71
internal/router/router.go
Normal file
@@ -0,0 +1,71 @@
|
||||
// Package router 负责 HTTP 路由注册,将请求分发到 Controller。
|
||||
package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"stock-analysis/internal/controller"
|
||||
)
|
||||
|
||||
// New 构建应用路由处理器。
|
||||
// webDir 为前端静态资源目录(View 层)。
|
||||
func New(mc *controller.MarketController, ac *controller.AuthController, webDir string) http.Handler {
|
||||
mux := http.NewServeMux()
|
||||
|
||||
// 公开接口:无需登录。
|
||||
mux.HandleFunc("POST /api/auth/send-code", ac.SendCode)
|
||||
mux.HandleFunc("POST /api/auth/register", ac.Register)
|
||||
mux.HandleFunc("POST /api/auth/login", ac.Login)
|
||||
|
||||
// 受保护接口:需要登录。
|
||||
mux.HandleFunc("GET /api/auth/me", ac.Me)
|
||||
mux.HandleFunc("POST /api/auth/logout", ac.Logout)
|
||||
mux.HandleFunc("GET /api/bonds", requireAuth(ac, mc.ListBonds))
|
||||
mux.HandleFunc("GET /api/bonds/{code}/kline", requireAuth(ac, mc.GetKline))
|
||||
mux.HandleFunc("POST /api/backtest", requireAuth(ac, mc.RunBacktest))
|
||||
mux.HandleFunc("GET /api/status", requireAuth(ac, mc.GetDataStatus))
|
||||
mux.HandleFunc("GET /api/db/bonds", requireAuth(ac, mc.ListDBBonds))
|
||||
|
||||
// 静态资源:登录页及样式脚本公开,首页受保护。
|
||||
fs := noCache(http.FileServer(http.Dir(webDir)))
|
||||
mux.Handle("/auth.html", fs)
|
||||
mux.Handle("/style.css", fs)
|
||||
mux.HandleFunc("/", requireAuth(ac, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/" && r.URL.Path != "/index.html" {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
http.ServeFile(w, r, filepath.Join(webDir, "index.html"))
|
||||
}))
|
||||
return mux
|
||||
}
|
||||
|
||||
// requireAuth 中间件:未登录的 API 请求返回 401,页面请求重定向到登录页。
|
||||
func requireAuth(ac *controller.AuthController, next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := ac.CurrentUser(r); err != nil {
|
||||
if strings.HasPrefix(r.URL.Path, "/api/") {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
fmt.Fprintf(w, `{"error":"%s"}`, err.Error())
|
||||
} else {
|
||||
http.Redirect(w, r, "/auth.html", http.StatusFound)
|
||||
}
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// noCache 中间件:禁止浏览器缓存静态资源,确保每次加载最新版本。
|
||||
func noCache(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||
w.Header().Set("Pragma", "no-cache")
|
||||
w.Header().Set("Expires", "0")
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user