Day4 使用grpc-gateway构建微服务网关 | 青训营笔记
这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天
进行微服务开发的时候会用到网关服务,而原生自己实现一个网关服务会显得费时费力,grpc官方提供了一个网关服务插件grpc-gateway
使用这个插件可以像生成grpc服务一样生成网关服务,同时它还支持生成openapi,这样就可以轻松集成swagger进行服务测试了
安装
使用grpc-gateway首先要安装几个代码生成工具,这几个代码生成工具时grpc用来根据protobuf生成代码用的
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest google.golang.org/protobuf/cmd/protoc-gen-go@latest google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
除此之外还要安装buf
工具,下载可以参考官方repo
buf可以使用yaml配置来简化生成代码的流程,只需要配置好yaml就可以使用命令buf generate
生成所有要用的代码
生成文件
新建一个项目,目录应该如下如下
├── buf.gen.yaml
├── buf.work.yaml
├── go.mod
├── main.go
└── proto
├── buf.yaml
buf.gen.yaml
version: v1
plugins:
# 根据protobuf文件生成go结构体
- remote: buf.build/library/plugins/go:v1.27.1-1
out: gen/go
opt:
- paths=source_relative
# 生成grpc相关文件
- remote: buf.build/library/plugins/go-grpc:v1.1.0-2
out: gen/go
opt:
- paths=source_relative
# 生成网关相关文件
- remote: buf.build/grpc-ecosystem/plugins/grpc-gateway:v2.6.0-1
out: gen/go
opt:
- paths=source_relative
# 生成openapi文档
- remote: buf.build/grpc-ecosystem/plugins/openapiv2:v2.6.0-1
out: gen/openapiv2
buf.work.yaml
在这个文件中directories
用于指定要根据哪些文件夹中的protobuf文件生成代码文件
version: v1
directories:
- proto
proto/buf.yaml
version: v1
deps:
# 添加一个会用到的依赖
- buf.build/googleapis/googleapis
之后在proto
文件夹中写protobuf文件
添加protobuf文件之前需要添加两个文件到proto
目录下的**google/api
**目录中
定义网关服务的时候会引用这两个文件
使用protobuf定义api的例子如下
syntax = "proto3";
package helloworld;
option go_package="./helloworld";
import "google/api/annotations.proto";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {
option (google.api.http) = {
post: "/v1/example/echo"
body: "*"
};
}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
原先定义一个服务,只需要定义服务的名称,参数列表和返回值列表
想要生成网关服务相关的代码,则还需要定义服务时添加option
选项
定义post请求时要像上面代码中定义的一样,在option
中定义一个post
,其值就是服务对应的网关路由
定义完了之后再当前目录运行
buf generate
就会生成相应的代码在gen
文件夹中
实现服务
在main.go
文件中修改代码
这步就是普通的实现grpc服务的
使用net.Listen
设置要监听的端口
然后用helloworldpb.RegisterGreeterServer
绑定自己写的服务实现
最后是用s.Serve(lis)
启动服务
package main
import (
// ...
"google.golang.org/grpc"
helloworldpb "github.com/myuser/myrepo/proto/helloworld"
)
type server struct{
helloworldpb.UnimplementedGreeterServer
}
func (s *server) SayHello(ctx context.Context, in *helloworldpb.HelloRequest) (*helloworldpb.HelloReply, error) {
return &helloworldpb.HelloReply{Message: in.Name + " world"}, nil
}
func main() {
lis, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalln("Failed to listen:", err)
}
s := grpc.NewServer()
helloworldpb.RegisterGreeterServer(s, &server{})
log.Println("Serving gRPC on 0.0.0.0:8080")
log.Fatal(s.Serve(lis))
}
添加网关
修改main.go
因为网关服务和grpc服务需要并行执行,因此需要用到协程
将最后的log.Fatal(s.Serve(lis))
放在一个新的协程中运行
如下
go func() {
log.Fatal(s.Serve(lis))
}()
然后在main函数后添加如下内容来注册网关服务
// 创建连接
conn, err := grpc.DialContext(
context.Background(),
"0.0.0.0:8080",
grpc.WithBlock(),
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
log.Fatalln("Failed to dial server:", err)
}
gwmux := runtime.NewServeMux()
// 注册网关服务
err = helloworldpb.RegisterGreeterHandler(context.Background(), gwmux, conn)
if err != nil {
log.Fatalln("Failed to register gateway:", err)
}
gwServer := &http.Server{
Addr: ":8090", // 定义网关服务的端口
Handler: gwmux,
}
log.Println("Serving gRPC-Gateway on http://0.0.0.0:8090")
log.Fatalln(gwServer.ListenAndServe())
然后启动服务即可
本文作者:七つ一旋桜
本文链接:https://www.cnblogs.com/poifa/p/17716923.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步