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 包机制,可以防止项目外部的代码导入这些包。这是构建可维护、高内聚项目的关键设计模式。
下图展示了项目各层之间的调用关系:
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 响应