使用了AI重构项目,并完善了一部分后台问题

This commit is contained in:
2026-08-05 04:47:11 +08:00
parent 146b6b1e6c
commit ac740c24fd
35 changed files with 2876 additions and 980 deletions
+67 -115
View File
@@ -6,6 +6,7 @@ import (
"io/fs"
"log"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
@@ -46,7 +47,7 @@ func main() {
cfg := config.New(dataDir)
// 初始化数据库
db, err := database.Init(cfg.DatabasePath)
db, err := database.Init(cfg.DatabasePath, cfg)
if err != nil {
log.Fatal("数据库初始化失败:", err)
}
@@ -104,6 +105,11 @@ func main() {
// 初始化API路由
api.SetupRoutes(r, db, cfg)
apiPort := os.Getenv("API_PORT")
if apiPort == "" {
apiPort = "1551"
}
// 创建前端服务器(1552端口)- 从嵌入的文件系统提供前端文件
frontendRouter := gin.New()
frontendRouter.Use(gin.Recovery())
@@ -114,7 +120,7 @@ func main() {
if err == nil {
// 使用嵌入的文件系统
frontendRouter.StaticFS("/static", http.FS(distRoot))
// 提供favicon
frontendRouter.GET("/favicon.ico", func(c *gin.Context) {
data, err := distRoot.Open("favicon.ico")
@@ -130,52 +136,13 @@ func main() {
}
c.Data(http.StatusOK, "image/x-icon", content)
})
// API代理:将/api请求代理到1551端口
frontendRouter.Any("/api/*path", func(c *gin.Context) {
client := &http.Client{
Timeout: 30 * time.Second,
}
targetURL := "http://localhost:1551" + c.Request.URL.Path
if c.Request.URL.RawQuery != "" {
targetURL += "?" + c.Request.URL.RawQuery
}
req, err := http.NewRequestWithContext(c.Request.Context(), c.Request.Method, targetURL, c.Request.Body)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "创建代理请求失败"})
return
}
for key, values := range c.Request.Header {
for _, value := range values {
req.Header.Add(key, value)
}
}
resp, err := client.Do(req)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": "代理请求失败: " + err.Error()})
return
}
defer resp.Body.Close()
for key, values := range resp.Header {
for _, value := range values {
c.Writer.Header().Add(key, value)
}
}
// 复制响应状态码和内容
c.Status(resp.StatusCode)
c.Header("Content-Type", resp.Header.Get("Content-Type"))
io.Copy(c.Writer, resp.Body)
})
// API代理:将/api请求转发到配置的API端口
frontendRouter.Any("/api/*path", proxyAPIRequest(apiPort))
// /uploads代理
frontendRouter.Static("/uploads", cfg.UploadDir)
// SPA路由支持
frontendRouter.NoRoute(func(c *gin.Context) {
path := c.Request.URL.Path
@@ -183,7 +150,7 @@ func main() {
c.Status(404)
return
}
// 尝试打开文件
filePath := strings.TrimPrefix(path, "/")
if filePath == "" {
@@ -217,7 +184,7 @@ func main() {
}
}
}
// 返回index.htmlSPA路由)
indexFile, err := distRoot.Open("index.html")
if err == nil {
@@ -232,7 +199,7 @@ func main() {
c.Status(http.StatusNotFound)
}
})
log.Println("使用嵌入的前端文件(单一可执行文件模式)")
} else {
// 回退到文件系统(开发模式)
@@ -241,36 +208,9 @@ func main() {
if _, err := os.Stat(distPath); err == nil {
frontendRouter.Static("/static", filepath.Join(distPath, "static"))
frontendRouter.StaticFile("/favicon.ico", filepath.Join(distPath, "favicon.ico"))
frontendRouter.Any("/api/*path", func(c *gin.Context) {
client := &http.Client{Timeout: 30 * time.Second}
targetURL := "http://localhost:1551" + c.Request.URL.Path
if c.Request.URL.RawQuery != "" {
targetURL += "?" + c.Request.URL.RawQuery
}
req, _ := http.NewRequestWithContext(c.Request.Context(), c.Request.Method, targetURL, c.Request.Body)
for key, values := range c.Request.Header {
for _, value := range values {
req.Header.Add(key, value)
}
}
resp, err := client.Do(req)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": "代理请求失败"})
return
}
defer resp.Body.Close()
for key, values := range resp.Header {
for _, value := range values {
c.Writer.Header().Add(key, value)
}
}
// 复制响应状态码和内容
c.Status(resp.StatusCode)
c.Header("Content-Type", resp.Header.Get("Content-Type"))
io.Copy(c.Writer, resp.Body)
})
frontendRouter.Any("/api/*path", proxyAPIRequest(apiPort))
frontendRouter.Static("/uploads", cfg.UploadDir)
frontendRouter.NoRoute(func(c *gin.Context) {
if !strings.HasPrefix(c.Request.URL.Path, "/api/") && !strings.HasPrefix(c.Request.URL.Path, "/uploads/") {
@@ -281,34 +221,7 @@ func main() {
} else if _, err := os.Stat("./dist"); err == nil {
frontendRouter.Static("/static", "./dist/static")
frontendRouter.StaticFile("/favicon.ico", "./dist/favicon.ico")
frontendRouter.Any("/api/*path", func(c *gin.Context) {
client := &http.Client{Timeout: 30 * time.Second}
targetURL := "http://localhost:1551" + c.Request.URL.Path
if c.Request.URL.RawQuery != "" {
targetURL += "?" + c.Request.URL.RawQuery
}
req, _ := http.NewRequestWithContext(c.Request.Context(), c.Request.Method, targetURL, c.Request.Body)
for key, values := range c.Request.Header {
for _, value := range values {
req.Header.Add(key, value)
}
}
resp, err := client.Do(req)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": "代理请求失败"})
return
}
defer resp.Body.Close()
for key, values := range resp.Header {
for _, value := range values {
c.Writer.Header().Add(key, value)
}
}
// 复制响应状态码和内容
c.Status(resp.StatusCode)
c.Header("Content-Type", resp.Header.Get("Content-Type"))
io.Copy(c.Writer, resp.Body)
})
frontendRouter.Any("/api/*path", proxyAPIRequest(apiPort))
frontendRouter.Static("/uploads", cfg.UploadDir)
frontendRouter.NoRoute(func(c *gin.Context) {
if !strings.HasPrefix(c.Request.URL.Path, "/api/") && !strings.HasPrefix(c.Request.URL.Path, "/uploads/") {
@@ -322,11 +235,6 @@ func main() {
}
// 启动两个服务器
apiPort := os.Getenv("API_PORT")
if apiPort == "" {
apiPort = "1551"
}
frontendPort := os.Getenv("FRONTEND_PORT")
if frontendPort == "" {
frontendPort = "1552"
@@ -335,7 +243,7 @@ func main() {
// 创建API服务器
apiServer := &http.Server{
Addr: ":" + apiPort,
Handler: r,
Handler: r,
}
// 创建前端服务器
@@ -372,9 +280,23 @@ func main() {
}
func corsMiddleware() gin.HandlerFunc {
allowedOrigins := make(map[string]struct{})
for _, origin := range strings.Split(os.Getenv("CORS_ALLOWED_ORIGINS"), ",") {
if value := strings.TrimSpace(origin); value != "" {
allowedOrigins[value] = struct{}{}
}
}
if len(allowedOrigins) == 0 {
allowedOrigins["http://localhost:1552"] = struct{}{}
allowedOrigins["http://127.0.0.1:1552"] = struct{}{}
}
return func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
origin := c.GetHeader("Origin")
if _, ok := allowedOrigins[origin]; ok {
c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Add("Vary", "Origin")
}
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE, PATCH")
@@ -386,3 +308,33 @@ func corsMiddleware() gin.HandlerFunc {
c.Next()
}
}
func proxyAPIRequest(apiPort string) gin.HandlerFunc {
client := &http.Client{Timeout: 30 * time.Second}
return func(c *gin.Context) {
target := &url.URL{Scheme: "http", Host: "localhost:" + apiPort, Path: c.Request.URL.Path, RawQuery: c.Request.URL.RawQuery}
req, err := http.NewRequestWithContext(c.Request.Context(), c.Request.Method, target.String(), c.Request.Body)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "创建代理请求失败"})
return
}
for key, values := range c.Request.Header {
for _, value := range values {
req.Header.Add(key, value)
}
}
resp, err := client.Do(req)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": "代理请求失败"})
return
}
defer resp.Body.Close()
for key, values := range resp.Header {
for _, value := range values {
c.Writer.Header().Add(key, value)
}
}
c.Status(resp.StatusCode)
_, _ = io.Copy(c.Writer, resp.Body)
}
}