
项目包含两个独立程序:
Go 客户端
↓ 发送请求
ConnectRPC 服务端
↓
Handler
↓
Service
↓
返回“你好,小明!”先运行全部测试:
go test ./...测试结果中的:
ok表示测试通过。
[no test files]表示这个 package 没有测试文件,并不是报错。
(cached)表示代码没有变化,Go 使用了之前的测试结果。想强制重新执行,可以使用:
go test -count=1 ./...Protobuf 可以理解为前后端共同遵守的“接口合同”。
在 .proto 文件中,我们定义:
service HelloService {
rpc SayHello(SayHelloRequest) returns (SayHelloResponse);
}
message SayHelloRequest {
string name = 1;
}
message SayHelloResponse {
string message = 1;
}这段代码表达的是:
接口名称:SayHello
请求参数:姓名
返回结果:问候语其中:
string name = 1;后面的 1 是字段编号,不是默认值。已经发布的字段编号不能随意更换或重复使用。
Protobuf 负责定义“双方说什么”,ConnectRPC 负责“双方怎样通过网络交流”。
二者的关系可以这样理解:
Protobuf:接口合同
ConnectRPC:通信工具
Go Service:具体业务逻辑ConnectRPC 根据 Protobuf 自动生成:
生成命令是:
buf generate生成结果位于:
gen/go/这个目录不能手工修改。正确流程是:
修改 .proto
→ buf lint
→ buf generate
→ 修改业务实现
→ 运行测试客户端创建请求:
request := connect.NewRequest(
&demov1.SayHelloRequest{
Name: "小明",
},
)然后调用远程方法:
response, err := client.SayHello(
context.Background(),
request,
)服务端收到请求后,进入 Handler:
message, err := h.service.Greet(
request.Msg.GetName(),
)业务层清理姓名并生成问候语:
func (Service) Greet(name string) (string, error) {
// 删除姓名首尾的空格。
name = strings.TrimSpace(name)
// 姓名为空时立即返回错误。
if name == "" {
return "", ErrEmptyName
}
// 正常生成问候语。
return fmt.Sprintf("你好,%s!", name), nil
}最终返回:
{
"message": "你好,小明!"
}今天理解了一个很重要的分层思想:
Handler:负责网络协议
Service:负责业务规则Handler 处理:
Service 处理:
这样做的好处是:业务逻辑不依赖具体网络框架。即使以后把 ConnectRPC 换成 REST API,Service 依然可以继续使用。
package main表示这是一个可以直接运行的程序。
package main
func main() {
// 程序从这里开始。
}:=声明变量,并让 Go 自动推断类型:
name := "小明"Go 函数可以同时返回结果和错误:
message, err := service.Greet("小明")成功时:
message = "你好,小明!"
err = nil失败时:
message = ""
err = ErrEmptyName* 和 &&SayHelloRequest{}& 表示取得对象所在的位置。
*HelloHandler* 表示这是一个指向 HelloHandler 的指针。
初学阶段可以先记住:Go 服务通常通过指针传递对象,避免复制,也方便共享和修改状态。
日志是在程序正常运行时记录过程:
slog.Info(
"SayHello 请求处理成功",
"name", name,
"message", message,
)Debug 则会在断点处暂停程序,让我们逐行执行并查看变量。
二者适合不同场景:
日志:事后查看程序发生了什么
Debug:现场观察程序正在做什么日志中不能随意记录密码、Token、API Key 和个人隐私。
以前看到 Protobuf、ConnectRPC、Handler 这些名词,会觉得它们离普通代码很远。
真正跑通最小项目后才发现,核心流程并不神秘:
定义接口
→ 生成代码
→ 客户端发送请求
→ Handler 接收请求
→ Service 执行业务
→ 返回响应复杂项目只是在这条主链路上加入了数据库、认证、异步任务和更多业务规则。
下一步,我会把这套最小流程映射到 ChainBridgev2,追踪一次真实的供应商查询请求。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。