2. Go Web 服务项目初始化

本章将带领你从零开始创建一个标准的 Go Web 服务项目。我们将使用 Go Modules 进行依赖管理,设计清晰的项目目录结构,并编写一个可运行的 HTTP 服务。这是后续所有 CI/CD 流水线、多环境部署和自动化测试的基础。

2.1 使用 Go Modules 创建项目

Go Modules 是 Go 官方推荐的依赖管理工具,自 Go 1.11 引入,Go 1.16 起默认启用。它解决了传统 GOPATH 模式下的依赖版本冲突和可重复构建问题。

2.1.1 初始化模块

在终端中执行以下命令,创建一个新的项目目录并初始化 Go Module:

mkdir go-web-cicd
cd go-web-cicd
go mod init github.com/your-username/go-web-cicd

执行后,项目根目录下会生成一个 go.mod 文件,内容类似:

module github.com/your-username/go-web-cicd

go 1.21
模块路径选择: 推荐使用 GitHub 仓库路径作为模块名,这样后续发布和引用都无需修改。如果只是本地学习,也可以使用 go-web-cicd 这样的简单名称。

2.1.2 添加依赖

当你在代码中 import 外部包并运行 go build 或 go test 时,Go 会自动下载依赖并更新 go.mod 和 go.sum 文件。例如,我们后续会使用 gorilla/mux 路由库:

go get github.com/gorilla/mux

此时 go.mod 会记录依赖版本,go.sum 会记录每个依赖的哈希值,确保构建一致性。

2.2 项目目录结构设计

一个良好的目录结构应当职责清晰、易于扩展。以下是本课程推荐的标准 Go Web 项目结构:

go-web-cicd/
├── cmd/
│   └── server/
│       └── main.go          # 应用入口
├── internal/
│   ├── handler/             # HTTP 处理器
│   │   └── health.go
│   ├── service/             # 业务逻辑层
│   │   └── user.go
│   ├── repository/          # 数据访问层
│   │   └── user.go
│   └── model/               # 数据模型
│       └── user.go
├── pkg/
│   └── config/              # 配置管理
│       └── config.go
├── migrations/              # 数据库迁移脚本
├── deploy/                  # 部署相关文件
│   ├── Dockerfile
│   └── docker-compose.yml
├── scripts/                 # 辅助脚本
│   └── init-db.sh
├── test/                    # 集成测试
│   └── integration_test.go
├── go.mod
├── go.sum
└── Makefile
目录/文件 职责 说明
cmd/ 应用入口 每个子目录对应一个可执行程序,如 cmd/server
internal/ 内部包 Go 编译器强制外部无法导入,保护核心逻辑
pkg/ 可导出公共库 可被外部项目引用的通用代码
migrations/ 数据库迁移 SQL 文件或迁移工具脚本
deploy/ 部署配置 Docker、Kubernetes、Compose 等文件
scripts/ 辅助脚本 初始化、备份、数据填充等
test/ 集成测试 端到端测试、性能测试
为什么用 internal/? Go 1.4 引入的 internal 包机制,可以防止项目外部的代码导入这些包。这是构建可维护、高内聚项目的关键设计模式。

下图展示了项目各层之间的调用关系:

Go Web 服务项目架构图 cmd/server/main.go internal/handler/ internal/service/ internal/repository/ internal/model/ 层级职责 入口:启动服务、注册路由 处理器:解析请求、调用服务 服务层:业务逻辑编排 仓储层:数据持久化 模型层:数据结构定义 依赖方向 入口 → 处理器 → 服务 服务 → 仓储 → 模型 关键原则 • 单向依赖 • 接口隔离 • 依赖注入

2.3 编写一个简单的 HTTP 服务

现在我们在 cmd/server/main.go 中编写一个最基本的 HTTP 服务,包含健康检查接口。

2.3.1 创建入口文件

首先创建目录结构:

mkdir -p cmd/server internal/handler

编写 cmd/server/main.go:

package main

import (
    "log"
    "net/http"
    "github.com/your-username/go-web-cicd/internal/handler"
)

func main() {
    mux := http.NewServeMux()

    // 注册路由
    mux.HandleFunc("GET /health", handler.HealthCheck)

    // 启动服务
    addr := ":8080"
    log.Printf("Server starting on %s", addr)
    if err := http.ListenAndServe(addr, mux); err != nil {
        log.Fatalf("Server failed: %v", err)
    }
}

2.3.2 编写健康检查处理器

创建 internal/handler/health.go:

package handler

import (
    "encoding/json"
    "net/http"
)

type HealthResponse struct {
    Status  string `json:"status"`
    Version string `json:"version"`
}

func HealthCheck(w http.ResponseWriter, r *http.Request) {
    resp := HealthResponse{
        Status:  "ok",
        Version: "1.0.0",
    }

    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    json.NewEncoder(w).Encode(resp)
}

2.3.3 运行与验证

在项目根目录执行:

go run ./cmd/server/

打开另一个终端,使用 curl 测试:

curl http://localhost:8080/health

预期返回:

{"status":"ok","version":"1.0.0"}
Go 1.22 新特性: 上面的路由写法 "GET /health" 是 Go 1.22 引入的模式语法,支持方法匹配和路径参数。如果你使用更早的 Go 版本,需要改为 mux.HandleFunc("/health", handler.HealthCheck) 并在处理器内手动判断方法。

2.4 本章小结

通过本章的学习,你已经完成了以下工作:

  • 使用 go mod init 初始化了项目模块
  • 设计了符合 Go 社区最佳实践的项目目录结构
  • 编写了一个包含健康检查接口的 HTTP 服务
  • 验证了服务可以正常启动并返回 JSON 响应