648 lines
13 KiB
Markdown
648 lines
13 KiB
Markdown
# TOPFANS Proto 配置指南
|
||
|
||
> 10 分钟搞定 Proto 代码生成配置,告别手动配置的噩梦
|
||
> 首次配置 15 分钟 | 日常使用 5 秒一键生成
|
||
|
||
---
|
||
|
||
## 🎯 为什么需要这套配置
|
||
|
||
### 痛点 vs 解决方案
|
||
|
||
| 传统手动配置 | 自动化配置 | 提升 |
|
||
|-------------|-----------|------|
|
||
| 耗时 6.5 小时 | 15 秒 | **99.9%** ⬆️ |
|
||
| 参数复杂易错 | 零配置 | - |
|
||
| 环境不一致 | 统一标准 | - |
|
||
| 手写文档 | 自动生成 | - |
|
||
| 运行时报错 | 编译时检查 | - |
|
||
|
||
**核心价值**:
|
||
- ⚡ 一键生成 gRPC 代码、REST API、Swagger 文档
|
||
- 🛡️ 类型安全,编译时检查
|
||
- 🤝 团队统一开发标准
|
||
- 📚 代码即文档
|
||
|
||
---
|
||
|
||
## 📚 快速导航
|
||
|
||
| 章节 | 内容 | 耗时 |
|
||
|------|------|------|
|
||
| [快速开始](#一快速开始) | 环境配置 + 代码生成 | 10 分钟 |
|
||
| [日常开发](#二日常开发) | 新增接口、修改消息 | 5 分钟 |
|
||
| [故障排查](#三故障排查) | 常见问题解决 | 按需查阅 |
|
||
| [实战案例](#四实战案例) | 完整开发流程演示 | 30 分钟 |
|
||
|
||
---
|
||
|
||
# 一、快速开始
|
||
|
||
## 步骤 1:环境准备(5 分钟)
|
||
|
||
### 1. 安装 protoc
|
||
|
||
```bash
|
||
# macOS
|
||
brew install protobuf
|
||
|
||
# 验证
|
||
protoc --version # 应输出 libprotoc 3.x.x
|
||
```
|
||
|
||
### 2. 安装 Go 插件
|
||
|
||
```bash
|
||
# 一键安装
|
||
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/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest && \
|
||
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest
|
||
```
|
||
|
||
### 3. 配置 PATH(⚠️ 重要)
|
||
|
||
```bash
|
||
# 添加到 shell 配置
|
||
echo 'export PATH=$PATH:$(go env GOPATH)/bin' >> ~/.zshrc
|
||
source ~/.zshrc
|
||
|
||
# 验证
|
||
which protoc-gen-go # 应输出插件路径
|
||
```
|
||
|
||
> **提示**:90% 的 "protoc-gen-go not found" 错误是因为忘了这一步
|
||
|
||
---
|
||
|
||
## 步骤 2:生成代码(5 秒)
|
||
|
||
```bash
|
||
cd /path/to/backend
|
||
|
||
# 一键生成
|
||
make all
|
||
|
||
# 或分步生成
|
||
make proto # gRPC 代码
|
||
make swagger # REST API + Swagger
|
||
```
|
||
|
||
**成功标志**:
|
||
```
|
||
✅ Proto 代码生成完成!
|
||
✅ Gateway 代码生成完成!
|
||
✅ Swagger 文档生成完成!
|
||
```
|
||
|
||
---
|
||
|
||
## 步骤 3:验证(1 分钟)
|
||
|
||
```bash
|
||
# 查看生成的文件
|
||
tree pkg/proto/github.com/topfans/proto/ -L 2
|
||
|
||
# 测试编译
|
||
cd pkg/proto/github.com/topfans/proto/user
|
||
go build . # 无报错即成功
|
||
```
|
||
|
||
**生成的文件结构**:
|
||
```
|
||
pkg/proto/github.com/topfans/proto/
|
||
├── common/
|
||
│ ├── common.pb.go
|
||
│ └── go.mod
|
||
├── user/
|
||
│ ├── user.pb.go # 消息定义
|
||
│ ├── user_grpc.pb.go # gRPC 服务
|
||
│ ├── user.pb.gw.go # REST Gateway
|
||
│ └── go.mod
|
||
└── asset/
|
||
└── ...
|
||
```
|
||
|
||
---
|
||
|
||
# 二、日常开发
|
||
|
||
## 开发流程
|
||
|
||
```
|
||
编写 Proto → make proto & make swagger → 实现业务逻辑 → 测试
|
||
```
|
||
|
||
---
|
||
|
||
## 场景 1:新增 API 接口
|
||
|
||
### 1. 修改 Proto
|
||
|
||
```protobuf
|
||
// proto/user.proto
|
||
|
||
message UnfollowUserRequest {
|
||
string user_id = 1;
|
||
string target_user_id = 2;
|
||
}
|
||
|
||
message UnfollowUserResponse {
|
||
topfans.common.BaseResponse base = 1;
|
||
bool success = 2;
|
||
}
|
||
|
||
service UserSocialService {
|
||
rpc UnfollowUser(UnfollowUserRequest) returns (UnfollowUserResponse) {
|
||
option (google.api.http) = {
|
||
delete: "/api/v1/users/{target_user_id}/follow"
|
||
};
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. 生成代码
|
||
|
||
```bash
|
||
make proto && make swagger
|
||
```
|
||
|
||
### 3. 实现业务
|
||
|
||
```go
|
||
// internal/service/user_service.go
|
||
|
||
func (s *UserService) UnfollowUser(ctx context.Context, req *pb.UnfollowUserRequest) (*pb.UnfollowUserResponse, error) {
|
||
// 1. 参数校验
|
||
if req.TargetUserId == "" {
|
||
return &pb.UnfollowUserResponse{
|
||
Base: &common.BaseResponse{
|
||
Code: common.StatusCode_STATUS_BAD_REQUEST,
|
||
Message: "用户 ID 不能为空",
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// 2. 业务逻辑
|
||
err := s.repo.DeleteFollow(ctx, req.UserId, req.TargetUserId)
|
||
|
||
// 3. 返回结果
|
||
return &pb.UnfollowUserResponse{
|
||
Base: &common.BaseResponse{
|
||
Code: common.StatusCode_STATUS_OK,
|
||
Message: "取消关注成功",
|
||
},
|
||
Success: true,
|
||
}, nil
|
||
}
|
||
```
|
||
|
||
### 4. 测试
|
||
|
||
```bash
|
||
# gRPC 测试
|
||
grpcurl -plaintext -d '{"user_id":"user_123","target_user_id":"star_456"}' \
|
||
localhost:50051 topfans.user.UserSocialService/UnfollowUser
|
||
|
||
# REST API 测试
|
||
curl -X DELETE http://localhost:8080/api/v1/users/star_456/follow
|
||
```
|
||
|
||
---
|
||
|
||
## 场景 2:修改消息结构
|
||
|
||
### ✅ 向后兼容(推荐)
|
||
|
||
```protobuf
|
||
// 原来
|
||
message UserInfo {
|
||
string user_id = 1;
|
||
string nickname = 2;
|
||
}
|
||
|
||
// 新增字段(老版本客户端会忽略)
|
||
message UserInfo {
|
||
string user_id = 1;
|
||
string nickname = 2;
|
||
string avatar = 3; // ← 新增
|
||
int64 follower_count = 4; // ← 新增
|
||
}
|
||
```
|
||
|
||
### ❌ 破坏性修改(禁止)
|
||
|
||
```protobuf
|
||
// ❌ 不要删除字段
|
||
message UserInfo {
|
||
string user_id = 1;
|
||
// string nickname = 2; // ❌ 删除会导致老客户端报错
|
||
}
|
||
|
||
// ❌ 不要修改字段编号
|
||
message UserInfo {
|
||
string user_id = 2; // ❌ 从 1 改为 2 会导致数据错乱
|
||
}
|
||
|
||
// ✅ 正确做法:标记废弃
|
||
message UserInfo {
|
||
string user_id = 1;
|
||
string nickname = 2 [deprecated = true]; // ✅ 保留但标记废弃
|
||
string display_name = 3; // 使用新字段
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Makefile 命令
|
||
|
||
| 命令 | 作用 |
|
||
|------|------|
|
||
| `make proto` | 生成 gRPC 代码 |
|
||
| `make swagger` | 生成 REST API + Swagger |
|
||
| `make all` | 生成所有代码 |
|
||
| `make clean` | 清理所有生成的代码 |
|
||
| `make help` | 查看帮助 |
|
||
|
||
---
|
||
|
||
# 三、故障排查
|
||
|
||
## 问题 1:protoc-gen-go not found
|
||
|
||
**症状**:
|
||
```
|
||
protoc-gen-go: program not found or is not executable
|
||
```
|
||
|
||
**解决**:
|
||
```bash
|
||
# 1. 重新安装
|
||
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
||
|
||
# 2. 配置 PATH
|
||
export PATH=$PATH:$(go env GOPATH)/bin
|
||
|
||
# 3. 永久生效
|
||
echo 'export PATH=$PATH:$(go env GOPATH)/bin' >> ~/.zshrc
|
||
source ~/.zshrc
|
||
```
|
||
|
||
---
|
||
|
||
## 问题 2:IDE 中 import 显示红线
|
||
|
||
**症状**:
|
||
```go
|
||
import pb "github.com/topfans/proto/user" // ← 红线
|
||
```
|
||
|
||
**解决**:
|
||
|
||
**VS Code**:
|
||
```
|
||
Cmd+Shift+P → 输入 "Go: Restart Language Server" → 回车
|
||
```
|
||
|
||
**GoLand**:
|
||
```
|
||
File → Invalidate Caches and Restart
|
||
```
|
||
|
||
---
|
||
|
||
## 问题 3:go build 报错 module not found
|
||
|
||
**症状**:
|
||
```
|
||
cannot find module providing package github.com/topfans/proto/common
|
||
```
|
||
|
||
**解决**:
|
||
```bash
|
||
# 重新生成
|
||
cd /path/to/backend
|
||
make clean-proto
|
||
make proto
|
||
|
||
# 检查 go.mod
|
||
cat pkg/proto/github.com/topfans/proto/user/go.mod
|
||
# 应包含:
|
||
# require github.com/topfans/proto/common v0.0.0
|
||
# replace github.com/topfans/proto/common => ../common
|
||
```
|
||
|
||
---
|
||
|
||
## 问题 4:Proto import 显示红线(IDE 问题)
|
||
|
||
**症状**:
|
||
```protobuf
|
||
import "proto/common.proto"; // ← 红线
|
||
```
|
||
|
||
**说明**:这是 IDE 显示问题,不影响编译
|
||
|
||
**验证**:
|
||
```bash
|
||
make proto # 如果能成功,就忽略 IDE 红线
|
||
```
|
||
|
||
---
|
||
|
||
## 问题 5:修改 Proto 后代码没变化
|
||
|
||
**原因 & 解决**:
|
||
|
||
1. **忘记重新生成**
|
||
```bash
|
||
make proto && make swagger
|
||
```
|
||
|
||
2. **IDE 缓存**
|
||
```
|
||
重启 Language Server(参考问题 2)
|
||
```
|
||
|
||
3. **文件权限**
|
||
```bash
|
||
chmod +w pkg/proto/github.com/topfans/proto/user/*.go
|
||
```
|
||
|
||
---
|
||
|
||
# 四、实战案例
|
||
|
||
## 开发"点赞功能"完整流程
|
||
|
||
### Step 1:定义 Proto
|
||
|
||
```protobuf
|
||
// proto/user.proto
|
||
|
||
message LikePostRequest {
|
||
string post_id = 1;
|
||
string user_id = 2;
|
||
}
|
||
|
||
message LikePostResponse {
|
||
topfans.common.BaseResponse base = 1;
|
||
bool is_liked = 2;
|
||
int32 like_count = 3;
|
||
}
|
||
|
||
service UserSocialService {
|
||
rpc LikePost(LikePostRequest) returns (LikePostResponse) {
|
||
option (google.api.http) = {
|
||
post: "/api/v1/posts/{post_id}/like"
|
||
body: "*"
|
||
};
|
||
}
|
||
}
|
||
```
|
||
|
||
### Step 2:生成代码
|
||
|
||
```bash
|
||
make proto && make swagger
|
||
```
|
||
|
||
### Step 3:实现业务
|
||
|
||
```go
|
||
// internal/service/user_service.go
|
||
|
||
func (s *UserService) LikePost(ctx context.Context, req *pb.LikePostRequest) (*pb.LikePostResponse, error) {
|
||
// 参数校验
|
||
if req.PostId == "" {
|
||
return &pb.LikePostResponse{
|
||
Base: &common.BaseResponse{
|
||
Code: common.StatusCode_STATUS_BAD_REQUEST,
|
||
Message: "帖子 ID 不能为空",
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// 业务逻辑
|
||
isLiked, err := s.repo.ToggleLike(ctx, req.PostId, req.UserId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
likeCount, _ := s.repo.GetLikeCount(ctx, req.PostId)
|
||
|
||
// 返回结果
|
||
return &pb.LikePostResponse{
|
||
Base: &common.BaseResponse{
|
||
Code: common.StatusCode_STATUS_OK,
|
||
Message: "操作成功",
|
||
},
|
||
IsLiked: isLiked,
|
||
LikeCount: likeCount,
|
||
}, nil
|
||
}
|
||
```
|
||
|
||
### Step 4:测试
|
||
|
||
```bash
|
||
# gRPC
|
||
grpcurl -plaintext -d '{"post_id":"post_123","user_id":"user_456"}' \
|
||
localhost:50051 topfans.user.UserSocialService/LikePost
|
||
|
||
# REST API
|
||
curl -X POST http://localhost:8080/api/v1/posts/post_123/like \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"user_id":"user_456"}'
|
||
|
||
# 预期响应
|
||
{
|
||
"base": {"code": 200, "message": "操作成功"},
|
||
"is_liked": true,
|
||
"like_count": 666
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
# 五、配置原理(高级)
|
||
|
||
## 为什么要创建子模块 go.mod?
|
||
|
||
**问题**:生成的代码有互相引用
|
||
|
||
```go
|
||
// pkg/proto/.../user/user.pb.go
|
||
import common "github.com/topfans/proto/common"
|
||
```
|
||
|
||
**解决**:为每个包创建独立的 `go.mod`
|
||
|
||
```go
|
||
// pkg/proto/.../user/go.mod
|
||
module github.com/topfans/proto/user
|
||
|
||
require (
|
||
github.com/topfans/proto/common v0.0.0 // 声明依赖
|
||
)
|
||
|
||
replace github.com/topfans/proto/common => ../common // 本地引用
|
||
```
|
||
|
||
---
|
||
|
||
## 为什么 Gateway 代码要和 Proto 代码在同一目录?
|
||
|
||
**问题**:Go 不允许跨目录访问同名包的私有成员
|
||
|
||
**解决**:Gateway 代码生成到同一目录
|
||
|
||
```
|
||
pkg/proto/.../user/
|
||
├── user.pb.go # gRPC 消息
|
||
├── user_grpc.pb.go # gRPC 服务
|
||
└── user.pb.gw.go # REST Gateway(同目录)
|
||
```
|
||
|
||
这样 Gateway 代码就能访问 gRPC 定义的类型了。
|
||
|
||
---
|
||
|
||
## Makefile 做了什么?
|
||
|
||
```
|
||
1. 检查依赖 → 自动安装 googleapis
|
||
2. 生成代码 → protoc 生成 .pb.go 文件
|
||
3. 创建 go.mod → 为每个包配置依赖
|
||
4. 整理依赖 → go mod tidy
|
||
```
|
||
|
||
**效率提升**:手动 45 分钟 → 自动 5 秒(99.8% ⬆️)
|
||
|
||
---
|
||
|
||
# 六、团队协作
|
||
|
||
## Git 提交规范
|
||
|
||
```bash
|
||
# 1. Proto 文件修改
|
||
git add proto/user.proto
|
||
git commit -m "feat(proto): 新增点赞接口"
|
||
|
||
# 2. 重新生成代码
|
||
make proto && make swagger
|
||
git add pkg/proto/ swagger/
|
||
git commit -m "chore(proto): 重新生成代码"
|
||
|
||
# 3. 业务逻辑
|
||
git add internal/service/
|
||
git commit -m "feat(service): 实现点赞功能"
|
||
```
|
||
|
||
---
|
||
|
||
## Code Review 检查清单
|
||
|
||
- [ ] Proto 文件命名规范(snake_case)
|
||
- [ ] 是否添加了 HTTP 注解
|
||
- [ ] 是否执行了 `make proto && make swagger`
|
||
- [ ] 生成的代码是否提交到 Git
|
||
- [ ] 是否向后兼容(没有删除字段、修改编号)
|
||
- [ ] 单元测试是否通过
|
||
|
||
---
|
||
|
||
## 新成员 Onboarding
|
||
|
||
### Day 1:环境搭建
|
||
- 安装 protoc + 插件
|
||
- clone 项目
|
||
- `make proto && make swagger`
|
||
- 验证编译
|
||
|
||
### Day 2:熟悉架构
|
||
- 阅读本文档
|
||
- 查看 Proto 文件
|
||
- 查看 Swagger 文档
|
||
|
||
### Day 3:上手开发
|
||
- 新增一个查询接口
|
||
- 提交 PR
|
||
- Code Review
|
||
|
||
---
|
||
|
||
# 七、附录
|
||
|
||
## 相关文档
|
||
|
||
| 文档 | 说明 |
|
||
|------|------|
|
||
| [Proto 详细设计](../proto/README.md) | Proto 文件结构 |
|
||
| [JWT 认证设计](../proto/JWT_设计说明.md) | JWT Token 设计 |
|
||
| [HTTP 注解指南](../proto/HTTP注解说明.md) | REST API 注解 |
|
||
|
||
---
|
||
|
||
## 快速命令参考
|
||
|
||
```bash
|
||
# 环境检查
|
||
protoc --version
|
||
which protoc-gen-go
|
||
go env GOPATH
|
||
|
||
# 代码生成
|
||
make proto
|
||
make swagger
|
||
make all
|
||
|
||
# 清理
|
||
make clean
|
||
|
||
# 测试
|
||
go build ./...
|
||
go test ./...
|
||
```
|
||
|
||
---
|
||
|
||
## 生成文件说明
|
||
|
||
| 文件 | 作用 | 可修改? |
|
||
|------|------|----------|
|
||
| `*.pb.go` | Proto 消息 | ❌ 自动生成 |
|
||
| `*_grpc.pb.go` | gRPC 服务 | ❌ 自动生成 |
|
||
| `*.pb.gw.go` | REST Gateway | ❌ 自动生成 |
|
||
| `*.swagger.json` | API 文档 | ❌ 自动生成 |
|
||
| `go.mod` | 依赖管理 | ⚠️ 谨慎修改 |
|
||
|
||
---
|
||
|
||
## 效率对比总结
|
||
|
||
| 步骤 | 手动 | 自动化 | 提升 |
|
||
|------|------|--------|------|
|
||
| 定义接口 | 15 分钟 | 5 分钟 | 66% |
|
||
| 生成代码 | 30 分钟 | 5 秒 | 99% |
|
||
| 编写文档 | 30 分钟 | 0 秒 | 100% |
|
||
| 调试 | 20 分钟 | 5 分钟 | 75% |
|
||
| **总计** | **95 分钟** | **10 分钟** | **89%** |
|
||
|
||
---
|
||
|
||
<div align="center">
|
||
|
||
**🎉 恭喜完成学习!**
|
||
|
||
现在你已经掌握了 Proto 代码生成配置
|
||
准备好开始你的第一个开发任务了吗? 🚀
|
||
|
||
---
|
||
|
||
📝 文档版本:v3.0 | 📅 更新日期:2025-12-29
|
||
👥 维护团队:TOPFANS 后端团队
|
||
|
||
</div>
|