Go-Zero 开发指南
📚 目录
- Go-Zero 简介
- 环境准备与安装
- 项目创建与目录结构
- 依赖管理(Go Modules) ⭐ 新手必读
- 核心文件说明
- 完整开发流程 ⭐⭐⭐
- 中间件使用
- 项目运行
- 常见问题
Go-Zero 简介
go-zero 是一个集成了:API 网关 + RPC + 中间件 + 代码生成 + 微服务治理 的 Go 微服务框架。
-
VSCode插件:Go: 语法高亮,用官方的就行。goctl:.api文件语法高亮,需要从VSCode下载.vsix格式导入到Cursor之类的工具中使用,因为它们好像并不自带,所以需要外部导入下。
核心特点
- ✅ 自动生成代码:API / RPC / Model 自动生成
- ✅ 内置中间件:限流、熔断、降级、日志
- ✅ 强制分层架构:handler → logic → model
- ✅ 非常适合:微服务 / 后端接口项目
环境准备与安装
1. 检查 Go 版本
go version # 推荐 >= 1.20
2. 安装 goctl 工具
go install github.com/zeromicro/go-zero/tools/goctl@latest
3. 验证安装
goctl --version
如果报错:zsh: command not found: goctl
macOS/Linux 解决方案:
# 1. 查看 GOPATH
go env GOPATH
# 2. 编辑 ~/.zshrc,添加:
export GOPATH=$(go env GOPATH)
export PATH=$PATH:$GOPATH/bin
# 3. 使配置生效
source ~/.zshrc
Windows 解决方案:
- 在系统环境变量的 Path 中添加:
%GOPATH%\bin
项目创建与目录结构
1. 创建项目
# 创建项目
goctl api new testproject
cd testproject
2. 目录结构
testproject/
├── api/ # API 定义文件(或根目录)
│ └── testproject.api # 接口定义文件
├── etc/ # 配置文件目录
│ └── testproject.yaml # 项目配置
├── internal/
│ ├── config/ # 配置结构体
│ ├── handler/ # HTTP 处理层(参数解析、返回)
│ ├── logic/ # 业务逻辑层(核心业务代码)
│ ├── svc/ # 服务上下文(依赖注入中心)
│ └── types/ # 请求/响应类型(自动生成)
├── testproject.go # 程序入口
├── go.mod # 依赖管理
└── go.sum # 依赖校验
3. 目录说明
| 目录/文件 | 作用 |
|---|---|
api/*.api | 定义所有 API 接口,goctl 根据此文件生成代码 |
etc/*.yaml | 配置文件(端口、数据库、Redis等) |
internal/handler/ | 只负责参数解析、调用 logic、返回结果 |
internal/logic/ | 核心业务代码,写在这里(数据库、Redis、业务判断) |
internal/svc/ | 依赖注入中心,存放 DB、Redis、Model 等实例 |
go.mod | 声明项目依赖(等价于 package.json) |
依赖管理(Go Modules)
⚠️ 创建项目后最常见的问题
错误信息:
could not import github.com/zeromicro/go-zero/rest/httpx
(no required module provides package "...")
原因: 等价于前端写了 import axios 但没 npm install
解决方案:
# 1. 进入项目根目录
cd testproject
# 2. 自动下载依赖(最重要!)
go mod tidy
# 3. 验证依赖已安装
cat go.mod | grep go-zero
# 4. 运行项目
go run .
记住这个公式:
go mod tidy # = npm install
go run . # = npm run dev
核心文件说明
1. 程序入口:testproject.go
package main
import (
"flag"
"fmt"
"testproject/internal/config"
"testproject/internal/handler"
"testproject/internal/svc"
"github.com/zeromicro/go-zero/rest"
"github.com/zeromicro/go-zero/core/conf"
)
var configFile = flag.String("f", "etc/testproject.yaml", "the config file")
func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
ctx := svc.NewServiceContext(c)
server := rest.MustNewServer(c.RestConf)
defer server.Stop()
handler.RegisterHandlers(server, ctx)
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
server.Start()
}
2. 接口定义:api/testproject.api ⭐⭐⭐
这是 go-zero 最核心的文件,所有接口都在这里定义!
syntax = "v1"
type (
LoginReq {
Username string `json:"username"`
Password string `json:"password"`
}
LoginResp {
Token string `json:"token"`
UserInfo UserInfo `json:"userInfo"`
}
UserInfo {
Id int64 `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
}
)
service testproject {
@handler LoginHandler
post /api/user/login (LoginReq) returns (LoginResp)
}
说明:
@handler指定处理函数名称post /api/user/login= POST 请求,路径是/api/user/login(LoginReq)= 请求参数类型returns (LoginResp)= 返回类型
💡 重要:修改
*.api文件后,需要运行goctl api go -api api/testproject.api -dir . -style gozero重新生成代码
3. 配置文件:etc/testproject.yaml
Name: testproject
Host: 0.0.0.0
Port: 8888
Mysql:
DataSource: root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local
Redis:
Host: 127.0.0.1:6379
Type: node
Pass: ""
DB: 0
Log:
ServiceName: testproject
Mode: file
Path: logs
Level: info
4. 服务上下文:internal/svc/servicecontext.go
依赖注入中心,所有依赖(DB、Redis、Model)都放在这里!
package svc
import (
"testproject/internal/config"
"testproject/internal/model"
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
type ServiceContext struct {
Config config.Config
DB sqlx.SqlConn
Redis *redis.Redis
UserModel model.UserModel
}
func NewServiceContext(c config.Config) *ServiceContext {
db := sqlx.NewMysql(c.Mysql.DataSource)
rds, err := redis.NewRedis(redis.RedisConf{
Host: c.Redis.Host,
Type: c.Redis.Type,
Pass: c.Redis.Pass,
DB: c.Redis.DB,
})
if err != nil {
panic("Redis 连接失败: " + err.Error())
}
userModel := model.NewUserModel(db, cache.CacheConf{
{RedisConf: redis.RedisConf{
Host: c.Redis.Host,
Type: c.Redis.Type,
Pass: c.Redis.Pass,
}},
})
return &ServiceContext{
Config: c,
DB: db,
Redis: rds,
UserModel: userModel,
}
}
完整开发流程
开发流程概览
1. 定义 API(testproject.api)
↓
2. 生成代码(goctl api go)
↓
3. 创建数据库表
↓
4. 生成 Model(goctl model mysql)
↓
5. 配置 ServiceContext(初始化依赖)
↓
6. 实现 Logic 层业务逻辑
↓
7. 添加中间件(认证等)
↓
8. 运行测试
步骤 1:定义 API
编辑 api/testproject.api:
syntax = "v1"
type (
LoginReq {
Username string `json:"username"`
Password string `json:"password"`
}
LoginResp {
Token string `json:"token"`
UserInfo UserInfo `json:"userInfo"`
}
UserInfo {
Id int64 `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
}
)
service testproject {
@handler LoginHandler
post /api/user/login (LoginReq) returns (LoginResp)
}
步骤 2:生成代码
goctl api go -api api/testproject.api -dir . -style gozero
生成的文件:
internal/handler/loginhandler.go- HTTP 处理器(自动生成)internal/logic/loginlogic.go- 业务逻辑(需要自己实现)internal/types/types.go- 请求/响应结构体(自动生成)
步骤 3:创建数据库表
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(255) NOT NULL,
`email` varchar(100) DEFAULT NULL,
`created_at` datetime DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
步骤 4:生成 Model 层
goctl model mysql datasource \
-url="root:123456@tcp(127.0.0.1:3306)/test" \
-table="user" \
-dir="./internal/model" \
-cache=true \
--style=gozero
生成的文件:
internal/model/usermodel.go- 用户数据模型(自动生成 CRUD 方法)
步骤 5:配置 ServiceContext
参考上面的 servicecontext.go 示例,初始化 DB、Redis、UserModel。
步骤 6:实现 Logic 层业务逻辑
编辑 internal/logic/loginlogic.go:
package logic
import (
"context"
"database/sql"
"errors"
"fmt"
"time"
"testproject/internal/model"
"testproject/internal/svc"
"testproject/internal/types"
"github.com/zeromicro/go-zero/core/logx"
"github.com/google/uuid"
"golang.org/x/crypto/bcrypt"
)
type LoginLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic {
return &LoginLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *LoginLogic) Login(req *types.LoginReq) (*types.LoginResp, error) {
// 1. 参数校验
if req.Username == "" || req.Password == "" {
return nil, errors.New("用户名或密码不能为空")
}
// 2. 查询用户(使用 Model 层,自动使用缓存)
user, err := l.svcCtx.UserModel.FindOneByUsername(l.ctx, req.Username)
if err != nil {
return nil, errors.New("用户名或密码错误")
}
// 3. 验证密码
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password))
if err != nil {
return nil, errors.New("用户名或密码错误")
}
// 4. 生成 Token
token := uuid.New().String()
// 5. 存储 Token 到 Redis(7天过期)
tokenKey := fmt.Sprintf("user:token:%s", token)
err = l.svcCtx.Redis.Setex(tokenKey, fmt.Sprintf("%d", user.Id), 7*24*3600)
if err != nil {
return nil, errors.New("登录失败,请重试")
}
// 6. 返回结果
return &types.LoginResp{
Token: token,
UserInfo: types.UserInfo{
Id: user.Id,
Username: user.Username,
Email: user.Email.String,
},
}, nil
}
步骤 7:Handler 层(自动生成)
Handler 是自动生成的,通常不需要修改:
// internal/handler/loginhandler.go(自动生成)
func LoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.LoginReq
if err := httpx.Parse(r, &req); err != nil {
httpx.Error(w, err)
return
}
l := logic.NewLoginLogic(r.Context(), svcCtx)
resp, err := l.Login(&req)
if err != nil {
httpx.Error(w, err)
} else {
httpx.OkJson(w, resp)
}
}
}
Handler 的职责:
- ✅ 解析请求参数
- ✅ 调用 Logic 层
- ✅ 返回响应
- ❌ 不写业务逻辑
中间件使用
认证中间件(Token 验证)
创建:internal/middleware/authmiddleware.go
package middleware
import (
"context"
"errors"
"net/http"
"strconv"
"strings"
"testproject/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/rest/httpx"
)
func AuthMiddleware(svcCtx *svc.ServiceContext) rest.Middleware {
return func(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// 跳过登录接口
if r.URL.Path == "/api/user/login" {
next(w, r)
return
}
// 从请求头获取 token
authHeader := r.Header.Get("Authorization")
token := strings.TrimPrefix(authHeader, "Bearer ")
token = strings.TrimSpace(token)
if token == "" {
httpx.Error(w, errors.New("未登录,请先登录"))
return
}
// 从 Redis 验证 token
tokenKey := "user:token:" + token
userIdStr, err := svcCtx.Redis.Get(tokenKey)
if err != nil || userIdStr == "" {
httpx.Error(w, errors.New("token 无效或已过期"))
return
}
// 将 userId 注入到请求上下文
userId, _ := strconv.ParseInt(userIdStr, 10, 64)
ctx := context.WithValue(r.Context(), "userId", userId)
next(w, r.WithContext(ctx))
}
}
}
在 Logic 层获取 userId:
// 从上下文获取 userId(由中间件注入)
userId := l.ctx.Value("userId").(int64)
注册中间件:testproject.go
func main() {
// ... 前面的代码 ...
// 注册中间件(在路由注册之前)
server.Use(middleware.AuthMiddleware(ctx))
handler.RegisterHandlers(server, ctx)
server.Start()
}
项目运行
1. 运行前必做:安装依赖
cd testproject
go mod tidy
2. 运行项目
# 方式 1:直接运行(推荐)
go run .
# 方式 2:指定配置文件
go run testproject.go -f etc/testproject.yaml
# 方式 3:编译后运行
go build -o testproject .
./testproject
成功标志:
Starting server at 0.0.0.0:8888...
3. 测试接口
# 测试登录接口
curl -X POST http://localhost:8888/api/user/login \
-H "Content-Type: application/json" \
-d '{"username":"test","password":"123456"}'
4. 常见运行错误
错误 1:不在项目根目录
go: cannot find main module
解决: cd testproject(确认有 go.mod)
错误 2:依赖未安装
no required module provides package
解决: go mod tidy
错误 3:端口被占用
bind: address already in use
解决: 修改配置文件端口或 kill -9 <PID>
常见问题
1. 依赖未安装(最常见)
问题: no required module provides package
解决:
go mod tidy
2. 修改 API 文件后代码未更新
解决:
goctl api go -api api/testproject.api -dir . -style gozero
3. 数据库字段类型不匹配
问题: 数据库字段是 NULL,但 Go 结构体是 string
解决: 使用 sql.NullString、sql.NullInt64 等类型
4. Token 验证失败
检查:
- Redis 中 token 是否存在:
redis-cli GET user:token:{token} - 请求头格式:
Authorization: Bearer {token} - 中间件是否正确注册
核心原则
- 分层清晰:Handler → Logic → Model
- Handler 不写业务:只负责参数解析和返回
- Logic 写业务:所有业务逻辑在 Logic 层
- 依赖注入:所有依赖通过 ServiceContext 注入
- 代码生成:使用 goctl 自动生成代码
参考: