topfans/backend/docs/Proto配置指南.md
2026-04-07 22:29:48 +08:00

648 lines
13 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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` | 查看帮助 |
---
# 三、故障排查
## 问题 1protoc-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
```
---
## 问题 2IDE 中 import 显示红线
**症状**
```go
import pb "github.com/topfans/proto/user" // ← 红线
```
**解决**
**VS Code**
```
Cmd+Shift+P → 输入 "Go: Restart Language Server" → 回车
```
**GoLand**
```
File → Invalidate Caches and Restart
```
---
## 问题 3go 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
```
---
## 问题 4Proto 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>