当我们使用微服务架构完成了项目后,出现以下这些问题时,需要使用grpc-gateway来完成把http请求转换为rpc请求
1. 有的项目可能需要向后兼容(老系统还是通过http接口访问)
2. 有的项目只支持JSON格式API的访问,不支持RPC
3. 现写了一套RPC代码,后面再写一套web 接口代码。--> 同样的逻辑要写两遍
grpc-gateway文档地址: github.com/grpc-ecosys…
这里简单介绍一下实现方法 ,首先要在你的proto文件中导入"google/api/annotations.proto"包,这个包默认是没有的,需要你自己去下载,也就是说你需要包的源码放在你的proto目录下
包的地址为 github.com/googleapis/…
以及
包中定义的内容可以帮助你使用 grpc-gateway
正确地将 HTTP 请求映射到你的 gRPC 服务方法
然后安装 gRPC-gateway相关插件
go install \
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway \
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2
以下是使用 grpc-gateway
的基本步骤:
-
编写 Protobuf 定义文件: 首先,你需要编写 gRPC 服务的 Protocol Buffers 定义文件,定义服务和消息。这里指定的对应关系是proto文件中描述的http与rpc服务的对应关系
service Goods{ rpc GetGoodsByRoom(GetGoodsByRoomReq) returns (GoodsListResp){ option (google.api.http) = { post: "/v1/goods" body: "*" }; };
-
生成 gRPC 代码: 使用
protoc
工具生成 gRPC 代码。
protoc \
--go_out=. \
--go_opt=paths=source_relative \
--go-grpc_out=. \
--go-grpc_opt=paths=source_relative \
--grpc-gateway_out=. \
--grpc-gateway_opt paths=source_relative \
3.定义一套gRPC服务
lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", config.Conf.IP, config.Conf.Port))
if err != nil {
panic(err)
}
// 创建gRPC服务
s := grpc.NewServer()
// 商品服务注册RPC服务
proto.RegisterGoodsServer(s, &handler.GoodsSrv{})
// 启动gRPC服务
go func() {
err = s.Serve(lis)
if err != nil {
panic(err)
}
}()
4.启动一个HTTP服务:接收外部的HTTP请求,Gateway生成一个反向代理,把http请求映射为rpc请求
//这里创建了一个新的 runtime.ServeMux 实例,它是 gRPC-Gateway 库提供的 HTTP 多路复用器。它用于将 HTTP 请求路由到相应的 gRPC 服务处理函数。
gwmux := runtime.NewServeMux()
//这里使用 proto.RegisterGoodsHandler 将 gRPC 服务 Goods 注册到 gwmux 上。conn 是 gRPC 客户端与 gRPC 服务之间的连接,它用于将 HTTP 请求转发到相应的 gRPC 服务方法。
err = proto.RegisterGoodsHandler(context.Background(), gwmux, conn)
if err != nil {
log.Fatalln("Failed to register gateway:", err)
}
//这里创建了一个 HTTP 服务器实例 gwServer,用于监听来自 gRPC-Gateway 的 HTTP 请求
gwServer := &http.Server{
Addr: ":8091",
Handler: gwmux,
}
zap.L().Info("Serving gRPC-Gateway on http://0.0.0.0:8091")
//启动http服务
go func() {
err := gwServer.ListenAndServe()
if err != nil {
log.Printf("gwServer.ListenAndServe failed, err: %v", err)
return
}
}()
5.把HTTP请求转为RPC请求,要有一个RPC client端
conn, err := grpc.DialContext( // RPC客户端
context.Background(),
fmt.Sprintf("%s:%d", config.Conf.IP, config.Conf.Port),
grpc.WithBlock(),
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
log.Fatalln("Failed to dial server:", err)
}
之后当我们用http请求(可以用postman测试)访问在proto文件定义的路由时,就可以访问相应的rpc服务。