基于 Gin 的 Go Web 应用框架,提供开箱即用的工程化基础设施。
- 模块化配置 — 13 个独立 YAML 文件,按职责隔离;
THINKGIN_*前缀环境变量覆盖 - 多数据源 — GORM 接入 MySQL/PostgreSQL/SQLite(SQLite 纯 Go,无 cgo)
- Redis 缓存 —
go-redis/v9多实例管理,启动期 Ping 探活 - 结构化日志 — Logrus + 按天文件轮转,JSON/Text 格式可选
- Prometheus 监控 — HTTP 四维 + 运行时 + 业务自定义指标,配置化启停
- 链路追踪 — OpenTelemetry TracerProvider;GORM 插件把 SQL 纳入同一条 trace
- 优雅停机 — 信号监听 + 超时 + DB/Cache/Tracer 依序释放,适配 Kubernetes
- K8s 探针 —
/livez仅验证进程存活;/readyz真实探测 DB/Redis,依赖降级时返 503 - 可插拔中间件 — Recovery、RequestID、AccessLog、CORS、RateLimit、Trace、Prometheus、Session
- Session 运行时 —
memory/redis两种 Store,Cookie 安全标志自动透传(HttpOnly/Secure/SameSite) - JWT 鉴权 — HS256 签发/校验,严格拒绝
alg=none伪造;JWTFromContext取 Claims
thinkgin/
├── main.go # 入口:Bootstrap → DB/Cache/Tracer → Run
├── framework/ # App 生命周期
│ ├── app.go
│ ├── options.go
│ └── browser.go
├── app/
│ ├── bootstrap.go # Bootstrap(configDir) 显式入口
│ ├── loader.go # 13 个 YAML 的泛型加载器
│ ├── env.go # THINKGIN_* 环境变量覆盖
│ ├── defaults.go # 零值默认填充
│ ├── validate.go # 语义校验与纠偏
│ ├── config.go / types.go # 全局 Config 单例 + 强类型
│ ├── logger.go # Logrus 初始化 + 跨平台文件轮转
│ ├── database/ # GORM 多数据源 + OTel 插件
│ ├── cache/ # Redis 多实例管理
│ └── index/ # 示例业务模块 (MVC)
│ ├── controller/
│ ├── model/ # 含 User 示例
│ └── view/
├── config/ # 13 个 YAML
├── route/ # 路由按 web / api 拆分
├── extend/middleware/
│ ├── api_response.go # 统一响应 + Recovery
│ ├── logger.go # RequestID + AccessLog
│ ├── cors.go / ratelimit.go
│ ├── trace.go # OTel TracerProvider 装配
│ └── prometheus*.go # 指标按 http/system/business/handler 拆分
├── .github/workflows/ci.yml # 三平台矩阵 + race + coverage
├── .golangci.yml # 精挑 linter
├── public/ # 静态资源
└── runtime/ # 运行时产物(日志)
- Go 1.25+(Gin 1.12 通过 quic-go 间接要求 Go 1.25)
- Git
# 克隆
git clone https://gitee.com/libaicode/thinkgin.git
cd thinkgin
# 配置 Go 代理(国内用户)
go env -w GOPROXY=https://goproxy.cn,direct
# 下载依赖
go mod tidy
# 运行
go run main.go启动后访问:
| 地址 | 说明 |
|---|---|
| http://localhost:8000 | 首页 |
| http://localhost:8000/index/hello | Hello World API |
| http://localhost:8000/metrics | Prometheus 指标 |
| http://localhost:8000/livez | 存活探针 |
# 本平台
go build -o thinkgin main.go
# 交叉编译
GOOS=linux GOARCH=amd64 go build -o thinkgin-linux main.go
GOOS=darwin GOARCH=arm64 go build -o thinkgin-darwin main.go所有配置位于 config/ 目录,每个文件独立管理一个模块:
| 文件 | 说明 |
|---|---|
app.yaml |
应用名、版本、JWT、分页 |
server.yaml |
监听地址、端口、超时、运行模式 |
database.yaml |
MySQL/PostgreSQL/SQLite 连接 |
cache.yaml |
Redis/内存缓存 |
log.yaml |
日志级别、格式、轮转策略 |
middleware.yaml |
全局中间件启用列表 |
prometheus.yaml |
监控指标、认证、采集间隔 |
trace.yaml |
链路追踪开关、采样率、导出方式 |
session.yaml |
会话存储(memory / redis 已可用) |
view.yaml |
模板引擎 |
filesystem.yaml |
文件存储(本地/OSS) |
lang.yaml |
国际化 |
route.yaml |
路由配置 |
所有核心配置支持 THINKGIN_ 前缀的环境变量覆盖:
THINKGIN_SERVER_MODE=release
THINKGIN_SERVER_HTTP_PORT=9090
THINKGIN_APP_DEBUG=false
THINKGIN_LOG_LEVEL=warn通过 config/middleware.yaml 配置启用:
middleware:
global:
- recovery
- request_id
- trace
- logger
- prometheus
- cors
- rate_limit// 计数器
if c := middleware.BusinessCounter("api_calls", []string{"endpoint"}); c != nil {
c.WithLabelValues("/api/users").Inc()
}
// 直方图
if h := middleware.BusinessHistogram("api_duration", []string{"endpoint"}, nil); h != nil {
h.WithLabelValues("/api/users").Observe(elapsed.Seconds())
}import (
"thinkgin/app/cache"
"thinkgin/app/database"
)
// 默认连接(对应 database.yaml 的 default 字段)
db := database.Default()
// 或按名取
pg, _ := database.Get("pgsql")
// Redis
rdb := cache.Default()GORM 插件会自动为每条 SQL 开启 span,并以当前 HTTP 请求的 trace 为父节点——
前提是业务代码用 db.WithContext(c.Request.Context()) 传递 context:
func ListUsers(c *gin.Context) {
var users []model.User
database.Default().WithContext(c.Request.Context()).Find(&users)
c.JSON(200, users)
}在 config/middleware.yaml 的 global 列表里加上 session,框架即自动挂载:
middleware:
global:
- recovery
- request_id
- session业务代码:
import "thinkgin/app/session"
func Profile(c *gin.Context) {
s := session.From(c)
s.Set("user_id", 42)
if err := s.Save(c.Request.Context()); err != nil {
c.AbortWithError(500, err)
return
}
c.JSON(200, gin.H{"ok": true})
}
func Logout(c *gin.Context) {
_ = session.From(c).Destroy(c.Request.Context())
session.ClearCookie(c)
c.JSON(200, gin.H{"ok": true})
}Store 切换仅需改 config/session.yaml:
| driver | 状态 | 适用场景 |
|---|---|---|
memory |
可用 | 单实例 / 开发调试 |
redis |
可用 | 多副本部署,引用 database.yaml 中的 redis 连接 |
file / database |
未实现 | — |
密钥配置在 config/app.yaml 的 app.jwt.secret;过期时间 app.jwt.expire(秒)。
import "thinkgin/extend/middleware"
// 签发(ttl=0 时使用 app.jwt.expire;仍为 0 时兜底 2 小时)
token, err := middleware.JWTIssue("42", map[string]any{"role": "admin"}, 0)
// 保护路由:middleware.yaml 的 global 里加 "jwt",或按 group 注入
api := r.Group("/api/v1", middleware.JWTAuth())
api.GET("/me", func(c *gin.Context) {
claims := middleware.JWTFromContext(c)
c.JSON(200, gin.H{"uid": claims.Subject})
})签名算法固定 HS256,解析时严格拒绝非 HMAC 算法,避免 alg=none 之类经典漏洞。
生成新的业务模块骨架(MVC 三件套):
go run ./cmd/scaffold new module user
# app/user/controller/user.go
# app/user/model/user.go
# app/user/view/.gitkeep命名规则:模块名必须以小写字母开头,只允许 a-z / 0-9 / _。
go test ./...
# 启用竞态检测(需要 cgo)
CGO_ENABLED=1 go test -race ./...仓库根目录的 .github/workflows/ci.yml 会在 push / PR 时跑:
- Build & Test:Ubuntu / Windows / macOS 三矩阵,启用
-race+ coverage - Lint:
golangci-lint,规则集见.golangci.yml
FROM golang:1.25-alpine AS builder
WORKDIR /app
COPY . .
RUN go mod tidy && go build -o thinkgin
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /app
COPY --from=builder /app/thinkgin .
COPY --from=builder /app/config ./config
EXPOSE 8000
CMD ["./thinkgin"]docker build -t thinkgin:3.0 .
docker run -p 8000:8000 thinkgin:3.0框架内置 /livez 和 /readyz 探针,可直接配置:
livenessProbe:
httpGet:
path: /livez
port: 8000
readinessProbe:
httpGet:
path: /readyz
port: 8000| 包 | 用途 |
|---|---|
| gin-gonic/gin v1.12 | HTTP 路由 |
| sirupsen/logrus v1.9 | 结构化日志 |
| prometheus/client_golang v1.20 | 监控指标 |
| go.opentelemetry.io/otel v1.28 | 链路追踪 |
| gorm.io/gorm v1.31 | ORM |
| redis/go-redis/v9 v9.18 | Redis 客户端 |
| glebarez/sqlite | SQLite 纯 Go 驱动 |
| lestrrat-go/file-rotatelogs | 日志轮转 |
| gopkg.in/yaml.v3 | YAML 解析 |
如果你之前用 ThinkPHP,建议阅读 docs/migration-from-thinkphp.md,
里面列出了最常见的 20+ 对照项(Model、Route、Middleware、Config、View 等)。
框架不内置迁移工具,推荐使用 pressly/goose。
用法与目录约定见 docs/database-migration.md。
一些反复被问到的问题和背后的取舍,集中写在 docs/faq.md:
- 为什么没有再封装一层"类 ThinkPHP 的 Model 链式调用"?
- 为什么 Redis 的连接定义放在
database.yaml,而不是cache.yaml? - 为什么默认配置不预置 MySQL / Redis 连接?
- 为什么
view.yaml/filesystem.yaml/lang.yaml里几乎是空的? - 为什么
init()里还保留了自动加载配置?
感谢 Gin 提供高性能的路由引擎。