当前位置: 首页 > 科技观察

Golang语言gRPC服务如何同时支持gRPC和HTTP客户端调用?

时间:2023-03-14 23:41:05 科技观察

01介绍gRPC相关文章。我们之前写过几篇文章。如果读者对gRPC还不是很了解,建议大家阅读公众号的历史文章。当我们需要为gRPC服务提供RESTfulAPI时,我们可以先创建一个gRPC客户端服务,在gRPC客户端服务中编写RESTfulAPI,在接收到HTTP请求时通过gRPC客户端服务调用gRPC服务器服务的方法.相信读者朋友们也意识到了,写一个gRPC客户端服务只是为了提供一个RESTfulAPI显然是有些小题大做了。gRPC服务端如何在不使用gRPC客户端服务的情况下同时支持gRPC和HTTP客户端调用?今天介绍一个protoc插件gRPC-Gateway。02gRPC-GatewaygRPC-Gateway是protoc的插件。它读取gRPC服务定义并生成将RESTfulJSONAPI转换为gRPC的反向代理服务器。该服务器是根据gRPC定义中的自定义选项生成的。gRPC-Gateway帮助您提供gRPC和RESTful风格的API。在我们开始编码之前,需要一些先决条件。首先,我们需要搭建一个Go环境。使用goget工具下载一些依赖。使用gomodinit工具创建一个go.mod文件。依赖包列表:$gogetgithub.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway$gogetgoogle.golang.org/protobuf/cmd/protoc-gen-go$gogetgoogle.golang.org/grpc/cmd/protoc-gen-go-grpc03gRPC-Gatewayinpractice在完成以上先决条件后,我们创建一个gRPC服务器服务。在本文中,我们创建了一个ToDoListgRPC服务。在创建gRPC服务之前,我们使用协议缓冲区创建一个原型文件。Createprotofile...serviceToDoList{rpcCreateToDoList(ToDoListDetail)returns(CreateToDoListResult){}rpcReadToDoList(ToDoListPage)returns(ReadToDoListByPage){}}...生成gRPCserverstub使用protoc命令工具生成stubprotoc-Iproto\--go_out./pb/todoPb--go_optpaths=source_relative\--go-grpc_out./pb/todoPb--go-grpc_optpaths=source_relative\proto/toDoList.proto执行上面的protoc命令工具生成一个*.pb.go文件和*_grpc.pb.go文件。编写剩余的Go代码来创建main.gofuncmain(){InitEngine()lis,err:=net.Listen("tcp",address)iferr!=nil{log.Fatalf("failedtolisten:%v",err)}server:=grpc.NewServer()pb.RegisterToDoListServer(server,new(service.ToDoList))log.Printf("serverlisteningat%v\n",lis.Addr())iferr:=服务器.Serve(lis);err!=nil{log.Fatalf("failedtoserve:%v",err)}}添加gRPC-Gateway选项gRPC-Gateway使用google.api.http选项来定义gRPC服务如何映射到JSON请求和响应,当使用protoc,每个RPC必须使用google.api.http选项定义HTTP方法和路径。因此,我们需要将google/api/http.proto导入添加到proto文件中。我们还需要添加所需的HTTP->gRPC映射。syntax="proto3";import"google/api/annotations.proto";serviceToDoList{rpcCreateToDoList(ToDoListDetail)returns(CreateToDoListResult){option(google.api.http)={post:"/v1/todolist/add"身体:”*”};}rpcReadToDoList(ToDoListPage)返回(ReadToDoListByPage){option(google.api.http)={get:"/v1/todolist/select"};}}...关于HTTP和gRPC映射更多信息可以参考GoogleAPI文档。生成gRPC-GatewayStub现在我们已经将gRPC-Gateway选项添加到proto文件中,我们需要使用gRPC-Gateway生成器来生成存根。在使用protoc生成存根之前,我们需要将一些依赖项复制到proto文件目录中。从官方存储库下载googleapis的子集并将其复制到本地proto文件目录中。如下:.├──dao│├──mysql.go│└──toDoList.go├──grpc-gateway│└──main.go├──main.go├──pb│└──todoPb│├──toDoList.pb.go│├──toDoList.pb.gw.go│└──toDoList_grpc.pb.go├──proto│├──google││└──api││├──注释.proto││└──http.proto│└──toDoList.proto└──service└──toDoList.go使用protoc生成stubprotoc-Iproto\--go_out./pb/todoPb--go_optpaths=source_relative\--go-grpc_out./pb/todoPb--go-grpc_opt路径=source_relative\--grpc-gateway_out./pb/todoPb--grpc-gateway_opt路径=source_relative\proto/toDoList.protoprotoc-go-inject-tag-XXX_skip=xorm-input=./pb/todoPb/toDoList.pb.go执行上面的protoc命令工具生成一个*.gw.pb.go文件。创建grpc-gateway目录,并创建main.go文件以创建gRPC-Gateway多路复用器。funcmain(){ctx:=context.Background()ctx,cancel:=context.WithCancel(ctx)defercancel()mux:=runtime.NewServeMux()opts:=[]grpc.DialOption{grpc.WithTransportCredentials(不安全.NewCredentials())}err:=pb.RegisterToDoListHandlerFromEndpoint(ctx,mux,grpcServerEndpoint,opts)iferr!=nil{log.Fatalf("无法注册gRPC网关服务端点:%v",err)}iferr=http.ListenAndServe(":8080",mux);err!=nil{log.Fatalf("CouldnotsetupHTTPendpoint:%v",err)}}startservicegrpcservicegorunmain.gogRPC-Gatewaygorungrpc-gateway/main.gocURL测试curlhttp://127.0.0.1:8080/v1/todolist/select?page=1&count=2响应结果:{"todolist":[{"id":"1","content":"编程编写代码","datetime":"1632541505","created":"1632541505","updated":"1632541505"},{"id":"2","content":"编程编写代码","datetime":"1632543373","created”:“1632543373","updated":"1632543373"}]}04总结本文介绍了gRPC-Gateway是如何实现同时支持gRPC和RESTful风格的API。当HTTP请求到达gRPC-Gateway时,gRPC-Gateway将JSON数据解析成protobuf消息.然后它使用解析的protobuf消息发出一个正常的GogRPC客户端请求.GogRPC客户端将protobuf结构编码成protobuf二进制格式并发送给gRPC服务器.gRPC服务器处理请求并在protobuf中返回响应二进制格式,GogRPC客户端解析成protobuf消息返回给gRPC-Gateway,gRPC-Gateway将protobuf消息编码成JSON返回给原始客户端图片来自gRPC-Gateway官方文档