Go-zero 安装与使用(详细流程)

197 阅读7分钟

Go-Zero 开发指南

📚 目录

  1. Go-Zero 简介
  2. 环境准备与安装
  3. 项目创建与目录结构
  4. 依赖管理(Go Modules) ⭐ 新手必读
  5. 核心文件说明
  6. 完整开发流程 ⭐⭐⭐
  7. 中间件使用
  8. 项目运行
  9. 常见问题

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.NullStringsql.NullInt64 等类型

4. Token 验证失败

检查:

  1. Redis 中 token 是否存在:redis-cli GET user:token:{token}
  2. 请求头格式:Authorization: Bearer {token}
  3. 中间件是否正确注册

核心原则

  1. 分层清晰:Handler → Logic → Model
  2. Handler 不写业务:只负责参数解析和返回
  3. Logic 写业务:所有业务逻辑在 Logic 层
  4. 依赖注入:所有依赖通过 ServiceContext 注入
  5. 代码生成:使用 goctl 自动生成代码

参考: