Go 网络编程:HTTP/2 与 gRPC
Go 语言标准库对 HTTP/2 有着原生且强大的支持,而 gRPC 则是基于 HTTP/2 构建的高性能 RPC 框架。掌握这两者的开发流程,是构建现代微服务架构的关键。
第一阶段:构建 HTTP/2 服务器
HTTP/2 相比 HTTP/1.1 具有多路复用、头部压缩等优势。在 Go 中,只需少量配置即可启用。
1. 生成自签名证书
HTTP/2 标准强制要求使用 TLS(传输层安全协议)。若没有域名和正规证书,需本地生成自签名证书用于测试。
打开 终端,执行 以下 OpenSSL 命令生成私钥文件 server.key 和证书文件 server.crt:
openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 365 -out server.crt
输入 提示所需的国家、城市等信息(测试用途可直接回车跳过)。
2. 编写 HTTP/2 服务端代码
Go 的 net/http 标准库在启用 TLS 时会自动协商使用 HTTP/2。
创建 文件 server.go,写入 以下代码:
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
// 定义处理函数
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// 检查是否为 HTTP/2 协议
if r.ProtoMajor == 2 {
fmt.Fprintf(w, "Welcome to HTTP/2 Protocol")
} else {
fmt.Fprintf(w, "Welcome to HTTP/1.1")
}
})
// 配置服务器结构体
server := &http.Server{
Addr: ":8443",
Handler: nil, // 使用 DefaultServeMux
}
// 启动 TLS 服务,ListenAndServeTLS 会自动启用 HTTP/2
log.Println("Server starting on https://localhost:8443")
log.Fatal(server.ListenAndServeTLS("server.crt", "server.key"))
}
运行 服务端:
go run server.go
3. 验证 HTTP/2 连接
由于使用自签名证书,使用 curl 时需加 -k 参数忽略证书验证。
执行 以下命令:
curl -k --http2 https://localhost:8443/
若输出 Welcome to HTTP/2 Protocol,则表明 HTTP/2 服务搭建成功。
第二阶段:gRPC 快速实战
gRPC 默认使用 Protocol Buffers (Protobuf) 作为接口定义语言 (IDL) 和消息交换格式。
1. 环境准备
安装 Protobuf 编译器 protoc 与 Go 代码生成插件。
执行 安装插件命令:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
更新 PATH 环境变量(若未自动添加):
export PATH="$PATH:$(go env GOPATH)/bin"
2. 定义 Protobuf 接口
创建 项目目录 grpc-demo,并在其中 创建 proto/service.proto 文件。
写入 以下定义:
syntax = "proto3";
package demo;
option go_package = "./pb";
// 定义服务接口
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// 定义请求消息
message HelloRequest {
string name = 1;
}
// 定义响应消息
message HelloReply {
string message = 1;
}
3. 生成 Go 代码
进入 项目根目录 grpc-demo,执行 编译命令:
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
proto/service.proto
确认 生成的文件:目录 proto/pb 下应出现 service.pb.go 和 service_grpc.pb.go 两个文件。
4. 实现 gRPC 服务端
初始化 Go 模块:
go mod init grpc-demo
go mod tidy
创建 server/main.go,实现 接口逻辑:
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"grpc-demo/proto/pb"
"log"
"net"
)
type server struct {
pb.UnimplementedGreeterServer
}
// 实现 SayHello 方法
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
return &pb.HelloReply{Message: fmt.Sprintf("Hello, %s! (via gRPC)", in.Name)}, nil
}
func main() {
// 监听 TCP 端口
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
// 创建 gRPC 服务器实例
s := grpc.NewServer()
// 注册服务
pb.RegisterGreeterServer(s, &server{})
log.Println("gRPC Server listening on :50051")
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
5. 编写 gRPC 客户端
创建 client/main.go,编写 调用逻辑:
package main
import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"grpc-demo/proto/pb"
"log"
)
func main() {
// 建立连接 (本例不使用 TLS,使用 insecure)
conn, err := grpc.Dial("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
// 创建客户端存根
c := pb.NewGreeterClient(conn)
// 调用远程方法
r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: "Developer"})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Server Response: %s", r.GetMessage())
}
6. 运行与测试
启动 服务端:
go run server/main.go
另开 终端窗口,运行 客户端:
go run client/main.go
查看 输出结果,若显示 Server Response: Hello, Developer! (via gRPC),则表示 gRPC 通信成功。
第三阶段:通信流程解析
gRPC 的调用过程封装了复杂的网络交互。以下是客户端调用服务端方法的完整流程示意。
核心差异对比
原生 HTTP/2 与 gRPC 在开发模式与性能特征上存在显著区别。
| 特性 | 原生 HTTP/2 (net/http) | gRPC |
|---|---|---|
| 数据格式 | 文本 (Header) + 二进制 (Body) | Protocol Buffers (二进制) |
| 代码生成 | 通常需手写 Handler | 自动生成 Client/Server 代码 |
| 连接类型 | 支持 HTTP/2 多路复用 | 强制 HTTP/2,长连接流式传输 |
| 适用场景 | 浏览器与服务端通信 | 微服务间高性能通信 |

暂无评论,快来抢沙发吧!