Go-Kratos 入门实战:从零实现用户 CRUD 服务

举报
golang学习记 发表于 2026/03/01 12:01:27 2026/03/01
【摘要】 🌟 一、Kratos 是什么?为什么选它?Kratos 是由 Bilibili 开源、社区共建的 Go 微服务开发框架,目标是让开发者专注于业务逻辑,不被基础设施拖累。 ✅ 四大核心优势能力说明技术实现Microservices独立部署、独立演进模块化布局 + 服务注册发现Specified API统一 API 定义Protobuf + 自动生成 HTTP/gRPC 接口Plug-abl...

🌟 一、Kratos 是什么?为什么选它?

Kratos 是由 Bilibili 开源、社区共建的 Go 微服务开发框架,目标是让开发者专注于业务逻辑,不被基础设施拖累。

✅ 四大核心优势

能力 说明 技术实现
Microservices 独立部署、独立演进 模块化布局 + 服务注册发现
Specified API 统一 API 定义 Protobuf + 自动生成 HTTP/gRPC 接口
Plug-able 插件化扩展 Tracing/Metrics/Log/RateLimit 按需装配

💡 一句话理解:
Kratos = Protobuf First + Clean Architecture + Cloud Native Ready


🛠️ 二、环境准备(含国内加速)

1. 安装 Go(≥ v1.23)

go version
# 推荐:1.24+

2. 安装 Kratos CLI

# 国外源(可能慢)
go install github.com/go-kratos/kratos/cmd/kratos/v2@latest

# ✅ 国内推荐:Gitee 源(更快)
go install -v github.com/go-kratos/kratos/cmd/kratos/v2@latest
# 若拉取失败,可手动设置 GOPROXY
export GOPROXY=https://goproxy.cn,direct

3. 安装 Protobuf 编译器 & 插件

# macOS
brew install protobuf

# Ubuntu
sudo apt install -y protobuf-compiler

# 安装 Go 插件(关键!)
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
go install github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2@latest
go install github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2@latest

✅ 验证安装:

kratos -v
# 输出示例:kratos version v2.7.2

🧱 三、创建项目骨架

# 使用 Gitee 源(国内友好)
kratos new user-service -r https://gitee.com/go-kratos/kratos-layout.git

cd user-service
go mod tidy

生成目录结构(精简关键部分):

user-service/
├── api/                # ← Protobuf API 定义
├── cmd/
│   └── user-service/   # ← 启动入口
├── internal/
│   ├── biz/            # ← 业务逻辑(UseCase)
│   ├── data/           # ← 数据访问(Repo/DB)
│   ├── service/        # ← 服务实现(对接 API)
│   └── server/         # ← HTTP/gRPC 服务注册
├── go.mod
└── Makefile

💡 布局理念:Clean Architecture 分层
API → Service → Biz → Data,依赖方向内聚,测试友好。


📝 四、定义用户 API(Protobuf)

1. 添加 Proto 文件

kratos proto add api/user/v1/user.proto

编辑 api/user/v1/user.proto

syntax = "proto3";

package api.user.v1;
option go_package = "user-service/api/user/v1;v1";

import "google/api/annotations.proto";
import "errors/errors.proto"; // ← 启用自定义错误

// 用户实体
message User {
  int64 id = 1;
  string name = 2;
  string email = 3;
  int32 age = 4;
}

// 请求/响应
message CreateUserRequest {
  string name = 1;
  string email = 2;
  int32 age = 3;
}
message CreateUserReply { User user = 1; }

message GetUserRequest { int64 id = 1; }
message GetUserReply { User user = 1; }

message UpdateUserRequest {
  int64 id = 1;
  string name = 2;
  string email = 3;
  int32 age = 4;
}
message UpdateUserReply { User user = 1; }

message DeleteUserRequest { int64 id = 1; }
message DeleteUserReply { bool ok = 1; }

message ListUserRequest { int32 page = 1; int32 size = 2; }
message ListUserReply { repeated User users = 1; }

// 错误定义(关键!)
extend google.protobuf.MethodOptions {
  kratos.api.Errors errors = 1111;
}

service UserService {
  rpc CreateUser(CreateUserRequest) returns (CreateUserReply) {
    option (google.api.http) = {
      post: "/v1/users"
      body: "*"
    };
  }
  rpc GetUser(GetUserRequest) returns (GetUserReply) {
    option (google.api.http) = {
      get: "/v1/users/{id}"
    };
    option (errors) = {
      rpc_error: [{
        code: 404,
        reason: "USER_NOT_FOUND",
        message: "user not found"
      }];
    };
  }
  rpc UpdateUser(UpdateUserRequest) returns (UpdateUserReply) {
    option (google.api.http) = {
      put: "/v1/users/{id}",
      body: "*"
    };
  }
  rpc DeleteUser(DeleteUserRequest) returns (DeleteUserReply) {
    option (google.api.http) = {
      delete: "/v1/users/{id}"
    };
  }
  rpc ListUser(ListUserRequest) returns (ListUserReply) {
    option (google.api.http) = {
      get: "/v1/users"
    };
  }
}

🔍 关键点:

  • google.api.http自动生成 RESTful 路由
  • errors/errors.proto + option (errors):生成类型安全的错误构造器(如 v1.ErrorUserNotFound().Err()

🧩 五、生成代码(Protobuf → Go)

 
# 或手动执行
kratos proto client api/user/v1/user.proto

生成文件:

api/user/v1/
├── user.pb.go          # Protobuf 序列化
├── user_grpc.pb.go     # gRPC 服务桩
└── user_http.pb.go     # HTTP 路由绑定(含参数解析)

✅ 此时 HTTP/gRPC 双协议接口已自动生成,无需手写路由


💼 六、分层实现:CRUD 逻辑

1. 定义业务模型 & 接口(internal/biz/user.go

package biz

import "context"

type User struct {
	ID    int64
	Name  string
	Email string
	Age   int32
}

// 仓库接口(Repo)
type UserRepo interface {
	Save(ctx context.Context, u *User) (*User, error)
	Get(ctx context.Context, id int64) (*User, error)
	Update(ctx context.Context, u *User) (*User, error)
	Delete(ctx context.Context, id int64) error
	List(ctx context.Context, page, size int32) ([]*User, error)
}

// 用例层(UseCase)
type UserUsecase struct {
	repo UserRepo
}

func NewUserUsecase(repo UserRepo) *UserUsecase {
	return &UserUsecase{repo: repo}
}

func (uc *UserUsecase) Create(ctx context.Context, u *User) (*User, error) {
	return uc.repo.Save(ctx, u)
}

func (uc *UserUsecase) Get(ctx context.Context, id int64) (*User, error) {
	u, err := uc.repo.Get(ctx, id)
	if err != nil {
		return nil, err
	}
	if u == nil {
		return nil, v1.ErrorUserNotFound("user not found").Err() // ← 类型安全错误
	}
	return u, nil
}

// Update/Delete/List 略(结构类似)

2. 实现数据层(内存模拟)—— internal/data/user.go

package data

import (
	"context"
	"sync/atomic"
	"user-service/internal/biz"
)

type userRepo struct {
	data map[int64]*biz.User
	seq  int64
}

func NewUserRepo() biz.UserRepo {
	return &userRepo{
		data: make(map[int64]*biz.User),
	}
}

func (r *userRepo) Save(ctx context.Context, u *biz.User) (*biz.User, error) {
	id := atomic.AddInt64(&r.seq, 1)
	u.ID = id
	r.data[id] = u
	return u, nil
}

func (r *userRepo) Get(ctx context.Context, id int64) (*biz.User, error) {
	u, ok := r.data[id]
	if !ok {
		return nil, nil // not found
	}
	return u, nil
}

func (r *userRepo) Update(ctx context.Context, u *biz.User) (*biz.User, error) {
	if _, exists := r.data[u.ID]; !exists {
		return nil, nil
	}
	r.data[u.ID] = u
	return u, nil
}

func (r *userRepo) Delete(ctx context.Context, id int64) error {
	delete(r.data, id)
	return nil
}

func (r *userRepo) List(ctx context.Context, page, size int32) ([]*biz.User, error) {
	var users []*biz.User
	for _, u := range r.data {
		users = append(users, u)
	}
	return users, nil
}

🔔 实际项目请替换为 GORM / Ent / sqlx + MySQL/PostgreSQL


3. 实现 Service 层(对接 API)—— internal/service/user.go

# 生成骨架(可选)
kratos proto server api/user/v1/user.proto -t internal/service

完善 internal/service/user.go

package service

import (
	"context"
	"user-service/api/user/v1"
	"user-service/internal/biz"
)

type UserService struct {
	v1.UnimplementedUserServiceServer // ← 嵌入未实现桩,避免漏方法
	uc *biz.UserUsecase
}

func NewUserService(uc *biz.UserUsecase) *UserService {
	return &UserService{uc: uc}
}

func (s *UserService) CreateUser(ctx context.Context, req *v1.CreateUserRequest) (*v1.CreateUserReply, error) {
	u := &biz.User{
		Name:  req.Name,
		Email: req.Email,
		Age:   req.Age,
	}
	created, err := s.uc.Create(ctx, u)
	if err != nil {
		return nil, err
	}
	return &v1.CreateUserReply{
		User: convertUser(created),
	}, nil
}

func (s *UserService) GetUser(ctx context.Context, req *v1.GetUserRequest) (*v1.GetUserReply, error) {
	u, err := s.uc.Get(ctx, req.Id)
	if err != nil {
		return nil, err
	}
	return &v1.GetUserReply{
		User: convertUser(u),
	}, nil
}

// 辅助转换函数
func convertUser(u *biz.User) *v1.User {
	return &v1.User{
		Id:    u.ID,
		Name:  u.Name,
		Email: u.Email,
		Age:   u.Age,
	}
}

// UpdateUser/DeleteUser/ListUser 略(类似)

⚙️ 七、注册服务 & 启动

1. 修改 internal/server/http.go

// 在 NewHTTPServer 中添加:
v1.RegisterUserServiceHTTPServer(srv, service.NewUserService(uc))

2. 修改 internal/server/grpc.go

// 在 NewGRPCServer 中添加:
v1.RegisterUserServiceServer(srv, service.NewUserService(uc))

3. 初始化依赖

// 在 main() 中:
repo := data.NewUserRepo()
uc := biz.NewUserUsecase(repo)
svc := service.NewUserService(uc)

// HTTP & gRPC server 启动时传入 svc
app := kratos.New(
	kratos.Name("user-service"),
	kratos.Server(
		httpSrv,
		grpcSrv,
	),
)

✅ 推荐使用 Wire 依赖注入(模板已生成 wire.go),避免手动 new。


▶️ 八、运行 & 测试

# 启动服务
go run ./cmd/user-service

# 默认端口:
#   HTTP:  :8000
#   gRPC:  :9000

🔧 使用 curl 测试(HTTP)

# 创建
curl -X POST http://localhost:8000/v1/users \
  -H "Content-Type: application/json" \
  -d '{"name":"Tom","email":"tom@example.com","age":30}'

# → {"user":{"id":1,"name":"Tom","email":"tom@example.com","age":30}}

# 获取
curl http://localhost:8000/v1/users/1

# 更新
curl -X PUT http://localhost:8000/v1/users/1 \
  -d '{"name":"Tom Lee","age":31}'

# 列表
curl "http://localhost:8000/v1/users?page=1&size=10"

# 删除
curl -X DELETE http://localhost:8000/v1/users/1

📚 总结

步骤 命令/操作
创建项目 kratos new user-service -r https://gitee.com/...
定义 API 编写 user.proto
生成代码 make apikratos proto client ...
实现逻辑 bizdataservice
启动测试 go run ./cmd/... + curl

✅ 你已掌握:

  • Kratos 核心开发流程
  • Protobuf First 工作流
  • HTTP & gRPC 双协议服务
  • 分层架构(Clean Architecture)
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。