首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Go 学习 Day 1:从零跑通 Protobuf 与 ConnectRPC

Go 学习 Day 1:从零跑通 Protobuf 与 ConnectRPC

原创
作者头像
dsy
发布于 2026-09-24 11:03:05
发布于 2026-09-24 11:03:05
280
举报

一、今天跑通了什么

项目包含两个独立程序:

代码语言:javascript
复制
Go 客户端
    ↓ 发送请求
ConnectRPC 服务端
    ↓
Handler
    ↓
Service
    ↓
返回“你好,小明!”

先运行全部测试:

代码语言:javascript
复制
go test ./...

测试结果中的:

代码语言:javascript
复制
ok

表示测试通过。

代码语言:javascript
复制
[no test files]

表示这个 package 没有测试文件,并不是报错。

代码语言:javascript
复制
(cached)

表示代码没有变化,Go 使用了之前的测试结果。想强制重新执行,可以使用:

代码语言:javascript
复制
go test -count=1 ./...

二、Protobuf 是什么

Protobuf 可以理解为前后端共同遵守的“接口合同”。

在 .proto 文件中,我们定义:

代码语言:javascript
复制
service HelloService {
  rpc SayHello(SayHelloRequest) returns (SayHelloResponse);
}

message SayHelloRequest {
  string name = 1;
}

message SayHelloResponse {
  string message = 1;
}

这段代码表达的是:

代码语言:javascript
复制
接口名称:SayHello
请求参数:姓名
返回结果:问候语

其中:

代码语言:javascript
复制
string name = 1;

后面的 1 是字段编号,不是默认值。已经发布的字段编号不能随意更换或重复使用。


三、ConnectRPC 是什么

Protobuf 负责定义“双方说什么”,ConnectRPC 负责“双方怎样通过网络交流”。

二者的关系可以这样理解:

代码语言:javascript
复制
Protobuf:接口合同
ConnectRPC:通信工具
Go Service:具体业务逻辑

ConnectRPC 根据 Protobuf 自动生成:

  • Go 请求与响应类型;
  • 服务端接口;
  • HTTP 路由;
  • Go 客户端;
  • 数据序列化和解析代码。

生成命令是:

代码语言:javascript
复制
buf generate

生成结果位于:

代码语言:javascript
复制
gen/go/

这个目录不能手工修改。正确流程是:

代码语言:javascript
复制
修改 .proto
→ buf lint
→ buf generate
→ 修改业务实现
→ 运行测试

四、一次请求经历了什么

客户端创建请求:

代码语言:javascript
复制
request := connect.NewRequest(
    &demov1.SayHelloRequest{
        Name: "小明",
    },
)

然后调用远程方法:

代码语言:javascript
复制
response, err := client.SayHello(
    context.Background(),
    request,
)

服务端收到请求后,进入 Handler:

代码语言:javascript
复制
message, err := h.service.Greet(
    request.Msg.GetName(),
)

业务层清理姓名并生成问候语:

代码语言:javascript
复制
func (Service) Greet(name string) (string, error) {
    // 删除姓名首尾的空格。
    name = strings.TrimSpace(name)

    // 姓名为空时立即返回错误。
    if name == "" {
        return "", ErrEmptyName
    }

    // 正常生成问候语。
    return fmt.Sprintf("你好,%s!", name), nil
}

最终返回:

代码语言:javascript
复制
{
  "message": "你好,小明!"
}

五、为什么要区分 Handler 和 Service

今天理解了一个很重要的分层思想:

代码语言:javascript
复制
Handler:负责网络协议
Service:负责业务规则

Handler 处理:

  • ConnectRPC 请求;
  • Protobuf 数据转换;
  • 网络错误码;
  • 响应包装。

Service 处理:

  • 清理姓名;
  • 判断姓名是否为空;
  • 生成问候语。

这样做的好处是:业务逻辑不依赖具体网络框架。即使以后把 ConnectRPC 换成 REST API,Service 依然可以继续使用。


六、今天接触的 Go 基础

package main

表示这是一个可以直接运行的程序。

代码语言:javascript
复制
package main

func main() {
    // 程序从这里开始。
}

:=

声明变量,并让 Go 自动推断类型:

代码语言:javascript
复制
name := "小明"

多返回值

Go 函数可以同时返回结果和错误:

代码语言:javascript
复制
message, err := service.Greet("小明")

成功时:

代码语言:javascript
复制
message = "你好,小明!"
err = nil

失败时:

代码语言:javascript
复制
message = ""
err = ErrEmptyName

指针 * 和 &

代码语言:javascript
复制
&SayHelloRequest{}

& 表示取得对象所在的位置。

代码语言:javascript
复制
*HelloHandler

* 表示这是一个指向 HelloHandler 的指针。

初学阶段可以先记住:Go 服务通常通过指针传递对象,避免复制,也方便共享和修改状态。


七、日志与 Debug

日志是在程序正常运行时记录过程:

代码语言:javascript
复制
slog.Info(
    "SayHello 请求处理成功",
    "name", name,
    "message", message,
)

Debug 则会在断点处暂停程序,让我们逐行执行并查看变量。

二者适合不同场景:

代码语言:javascript
复制
日志:事后查看程序发生了什么
Debug:现场观察程序正在做什么

日志中不能随意记录密码、Token、API Key 和个人隐私。


八、今天最大的收获

以前看到 Protobuf、ConnectRPC、Handler 这些名词,会觉得它们离普通代码很远。

真正跑通最小项目后才发现,核心流程并不神秘:

代码语言:javascript
复制
定义接口
→ 生成代码
→ 客户端发送请求
→ Handler 接收请求
→ Service 执行业务
→ 返回响应

复杂项目只是在这条主链路上加入了数据库、认证、异步任务和更多业务规则。

下一步,我会把这套最小流程映射到 ChainBridgev2,追踪一次真实的供应商查询请求。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、今天跑通了什么
  • 二、Protobuf 是什么
  • 三、ConnectRPC 是什么
  • 四、一次请求经历了什么
  • 五、为什么要区分 Handler 和 Service
  • 六、今天接触的 Go 基础
    • package main
    • :=
    • 多返回值
    • 指针 * 和 &
  • 七、日志与 Debug
  • 八、今天最大的收获
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档