vault backup: 2026-05-13 11:17:21
This commit is contained in:
@@ -414,6 +414,45 @@ go generate ./...
|
||||
> [!tip] 为什么推荐 go generate?
|
||||
> 相比手写 protoc 命令,`go generate` 让代码生成变成 Go 工作流的一部分,不再需要额外记忆复杂的命令行参数。结合 Makefile 或 Task 更稳定。参见 [[hhs/gRPC/6. 工程实践篇/17-protoc 工具链与 Makefile]]。
|
||||
|
||||
## 实践要点:自动生成 vs 手写
|
||||
|
||||
### 自动生成(由 protoc 产出,不要手动修改)
|
||||
|
||||
| 文件 | 内容 |
|
||||
|------|------|
|
||||
| `xxx_pb.go` | Message struct 定义 + getter 方法(如 `CreateUserRequest{}`、`GetName()`) |
|
||||
| `xxx_grpc.pb.go` | Client Stub interface + `NewUserServiceClient()` |
|
||||
| `xxx_grpc.pb.go` | Server Interface(如 `UserServiceServer{ CreateUser(...) }`) |
|
||||
| `xxx_grpc.pb.go` | Register 函数 + ServiceDesc 元数据 |
|
||||
| `xxx_grpc.pb.go` | `UnimplementedUserServiceServer` 零值安全基类 |
|
||||
|
||||
这些文件**每次 `.proto` 变更后重新生成即可覆盖**。如果发现有 bug,修复源头 `.proto` 后重新生成,而不是直接改生成的文件。
|
||||
|
||||
### 开发者手写的部分
|
||||
|
||||
```go
|
||||
// ① 服务端:实现生成的 Server Interface
|
||||
type server struct {
|
||||
v1.UnimplementedUserServiceServer // ← 嵌入自动生成的基类
|
||||
store *UserStore // ← 自己的依赖注入
|
||||
}
|
||||
func (s *server) CreateUser(ctx, req *v1.CreateUserRequest) (*v1.CreateUserResponse, error) {
|
||||
// ← 填充业务逻辑(数据库操作、验证、权限等)
|
||||
}
|
||||
|
||||
// ② 客户端:使用生成的 Client Stub 发起调用
|
||||
client := v1.NewUserServiceClient(conn) // ← 用生成的函数创建
|
||||
resp, _ := client.CreateUser(ctx, &v1.CreateUserRequest{Name: "Alice"})
|
||||
|
||||
// ③ Server 启动注册
|
||||
v1.RegisterUserServiceServer(s, &myServer{})
|
||||
|
||||
// ④ 中间件、拦截器、错误映射、健康检查等——全部自行实现
|
||||
```
|
||||
|
||||
> [!important] 核心原则
|
||||
> **所有业务代码都应假设生成的 `.pb.go` / `_grpc.pb.go` 随时会被重新生成覆盖。** 不自行定义与 proto 同名的 struct;类型统一从生成的包 import;不修改任何生成的文件。
|
||||
|
||||
## 常见错误排查
|
||||
|
||||
| 错误信息 | 原因 | 解决方法 |
|
||||
|
||||
Reference in New Issue
Block a user