Files
stock-analysis/internal/router/router.go
WarrenZhou 273fc90a95 feat: 添加异步数据入库任务系统,支持全量/增量更新与实时进度展示
新增完整的异步任务管理体系:
1. 新增Redis缓存层实现任务状态实时存储与降级机制
2. 实现并发拉取+批量写入的高性能入库流程
3. 添加任务管理HTTP接口与路由
4. 重构行情控制器使用共享SQLite存储
5. 配套添加Docker Compose Redis启动配置
6. 前端新增任务管理面板支持操作与进度查看
2026-08-18 10:09:52 +08:00

78 lines
2.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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, tc *controller.TaskController, 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))
// 数据入库任务接口:创建/查询/取消(需要登录)。
mux.HandleFunc("POST /api/tasks", requireAuth(ac, tc.CreateTask))
mux.HandleFunc("GET /api/tasks", requireAuth(ac, tc.ListTasks))
mux.HandleFunc("GET /api/tasks/{id}", requireAuth(ac, tc.GetTask))
mux.HandleFunc("POST /api/tasks/{id}/cancel", requireAuth(ac, tc.CancelTask))
// 静态资源:登录页及样式脚本公开,首页受保护。
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)
})
}