Golang中配置文件和路由文件的存放位置应该在哪里

Golang中配置文件和路由文件的存放位置应该在哪里 你好,

我当前的应用程序结构如下所示。我的问题是关于 config.gorouter.go 文件。我想知道,就 Go 语言而言,它们是否放错了位置。config.go 文件一次性从 .env 文件加载应用程序配置变量。router.go 文件列出了 HTTP 服务器的所有端点路由,它们也是一次性加载的。

它们的位置正确吗?还是它们应该属于 /cmd/api//internal/app/ 文件夹?

注意:目前 main.go 被设计为一个“引导”文件,负责准备应用程序的依赖项。api.go 文件负责启动和关闭 HTTP 服务器。基于当前的设置,我强烈感觉 config.gorouter.go 文件应该属于 /cmd/api/ 文件夹,因为它们是引导流程的一部分,但我仍然需要经验丰富的意见。

谢谢

api
  |_ cmd
    |_ api
      |_ main.go
  |_ internal
    |_ app
    | |_ api.go
    |_ league
    | |_ create.go
    | |_ read.go
    |_ team
    | |_ update.go
    | |_ delete.do
    |_ pkg
      |_ config
      |  |_ config.go
      |_ router
         |_ router.go
Makefile
Readme.md
.env

我尽力遵循这个规范。


更多关于Golang中配置文件和路由文件的存放位置应该在哪里的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中配置文件和路由文件的存放位置应该在哪里的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


根据你的项目结构和描述,config.gorouter.go的当前位置是合理的,但可以进一步优化。让我分析一下:

当前结构分析

你当前的布局基本遵循了标准项目结构:

  • /cmd/api/main.go - 入口点 ✅
  • /internal/app/api.go - 应用启动逻辑 ✅
  • /internal/pkg/config/config.go - 配置加载 ✅
  • /internal/pkg/router/router.go - 路由定义 ✅

建议的调整方案

方案1:保持当前结构(推荐)

如果你希望严格遵循internal包的封装原则,当前结构是合适的:

// internal/pkg/config/config.go
package config

import (
    "github.com/joho/godotenv"
    "log"
    "os"
)

type Config struct {
    Port     string
    DBURL    string
    JWTSecret string
}

func Load() (*Config, error) {
    if err := godotenv.Load(); err != nil {
        log.Println("No .env file found")
    }
    
    return &Config{
        Port:     getEnv("PORT", "8080"),
        DBURL:    getEnv("DATABASE_URL", ""),
        JWTSecret: getEnv("JWT_SECRET", ""),
    }, nil
}

func getEnv(key, defaultValue string) string {
    if value := os.Getenv(key); value != "" {
        return value
    }
    return defaultValue
}
// internal/pkg/router/router.go
package router

import (
    "github.com/gorilla/mux"
    "net/http"
)

func NewRouter() *mux.Router {
    r := mux.NewRouter()
    
    // API路由
    api := r.PathPrefix("/api/v1").Subrouter()
    api.HandleFunc("/leagues", createLeague).Methods("POST")
    api.HandleFunc("/leagues/{id}", readLeague).Methods("GET")
    api.HandleFunc("/teams/{id}", updateTeam).Methods("PUT")
    api.HandleFunc("/teams/{id}", deleteTeam).Methods("DELETE")
    
    // 健康检查
    r.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusOK)
        w.Write([]byte("OK"))
    }).Methods("GET")
    
    return r
}

方案2:移动到/internal/app/

如果配置和路由是应用核心逻辑的一部分:

api
  |_ cmd
    |_ api
      |_ main.go
  |_ internal
    |_ app
    | |_ api.go
    | |_ config.go    # 移动到这里
    | |_ router.go    # 移动到这里
    |_ league
    | |_ create.go
    | |_ read.go
    |_ team
    | |_ update.go
    | |_ delete.go

方案3:精简结构

对于中小型项目,可以更简化:

api
  |_ cmd
    |_ api
      |_ main.go
  |_ internal
    |_ app
    | |_ api.go
    | |_ config
    | |  |_ config.go
    | |_ router
    |    |_ router.go
    |_ league
    | |_ create.go
    | |_ read.go
    |_ team
    | |_ update.go
    | |_ delete.go

使用示例

// cmd/api/main.go
package main

import (
    "log"
    "your-project/internal/app"
    "your-project/internal/pkg/config"
)

func main() {
    // 加载配置
    cfg, err := config.Load()
    if err != nil {
        log.Fatal("Failed to load config:", err)
    }
    
    // 启动应用
    if err := app.Run(cfg); err != nil {
        log.Fatal("Application failed:", err)
    }
}
// internal/app/api.go
package app

import (
    "context"
    "log"
    "net/http"
    "os"
    "os/signal"
    "syscall"
    "time"
    "your-project/internal/pkg/config"
    "your-project/internal/pkg/router"
)

func Run(cfg *config.Config) error {
    // 创建路由器
    r := router.NewRouter()
    
    // 创建HTTP服务器
    srv := &http.Server{
        Addr:    ":" + cfg.Port,
        Handler: r,
    }
    
    // 优雅关闭
    go func() {
        if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Fatalf("Server failed: %v", err)
        }
    }()
    
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    <-quit
    
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    
    return srv.Shutdown(ctx)
}

结论

你的当前结构/internal/pkg/config//internal/pkg/router/是合理的,特别是:

  1. 配置和路由确实属于基础设施层
  2. internal/pkg表明这些是内部共享包
  3. 保持了cmd/api/main.go的简洁性

如果你觉得这些是应用核心逻辑而非共享基础设施,可以考虑方案2。但当前结构已经很好地遵循了关注点分离原则。

回到顶部