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

简介: Golang 语言 gRPC 服务怎么同时支持 gRPC 和 HTTP 客户端调用?

01

介绍

关于 gRPC 的文章,我们之前写过几篇,如果读者朋友还对 gRPC 不了解,我建议您可以翻阅一下公众号的历史文章。

当我们需要提供 gRPC 服务的 RESTful API 时,可以先创建一个 gRPC 客户端服务,在 gRPC 客户端服务编写 RESTful API,接收到 HTTP 请求时,通过 gRPC 客户端服务调用 gRPC 服务端服务的方法。

相信读者朋友们也意识到,仅仅为了提供 RESTful API 而编写一个 gRPC 客户端服务,显然有些小题大做。

在不借助 gRPC 客户端服务的前提下,gRPC 服务端服务怎么同时支持 gRPC 和 HTTP 客户端调用?今天我们介绍一个 protoc 插件 gRPC-Gateway。

gRPC-Gateway

gRPC-Gateway 是 protoc 的一个插件。它读取 gRPC 服务定义并生成一个反向代理服务器,该服务器将 RESTful JSON API 转换为 gRPC。此服务器是根据 gRPC 定义中的自定义选项生成的。

gRPC-Gateway 可帮助您同时以 gRPC 和 RESTful 风格提供 API。

在我们开始编码之前,需要一些先决条件。

  1. 首先,我们需要先搭建一个 Go 环境。
  2. 使用 go get 工具下载一些依赖包。
  3. 使用 go mod init 工具创建一个 go.mod 文件。

依赖包列表:

$ go get github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway
$ go get google.golang.org/protobuf/cmd/protoc-gen-go
$ go get google.golang.org/grpc/cmd/protoc-gen-go-grpc

03

gRPC-Gateway 实战

在完成以上先决条件后,我们创建一个 gRPC 服务端服务,本文我们创建一个 ToDoList gRPC 服务。在创建 gRPC 服务之前,我们使用 protocol buffers 创建一个 proto 文件。

创建 proto 文件

...
service ToDoList {
  rpc CreateToDoList (ToDoListDetail) returns (CreateToDoListResult) {}
  rpc ReadToDoList (ToDoListPage) returns (ReadToDoListByPage) {}
}
...

生成 gRPC 服务端存根

使用 protoc 命令工具生成存根

protoc -I proto \
   --go_out ./pb/todoPb --go_opt paths=source_relative \
   --go-grpc_out ./pb/todoPb --go-grpc_opt paths=source_relative \
   proto/toDoList.proto

执行上面 protoc 命令工具,生成一个 *.pb.go 文件和一个 *_grpc.pb.go 文件。

编写剩余 Go 代码

创建 main.go

func main() {
 InitEngine()
 lis, err := net.Listen("tcp", address)
 if err != nil {
  log.Fatalf("failed to listen: %v", err)
 }
 server := grpc.NewServer()
 pb.RegisterToDoListServer(server, new(service.ToDoList))
 log.Printf("server listening at %v\n", lis.Addr())
 if err := server.Serve(lis); err != nil {
  log.Fatalf("failed to serve: %v", err)
 }
}

完整代码,请参阅 Github。

添加 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";
service ToDoList {
  rpc CreateToDoList (ToDoListDetail) returns (CreateToDoListResult) {
    option (google.api.http) = {
      post: "/v1/todolist/add"
      body: "*"
    };
  }
  rpc ReadToDoList (ToDoListPage) returns (ReadToDoListByPage) {
    option (google.api.http) = {
      get: "/v1/todolist/select"
    };
  }
}
...

关于 HTTP 和 gRPC 映射的更多内容,可以参阅 Google API 文档。

生成 gRPC-Gateway 存根

现在,我们已将 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
│   │       ├── annotations.proto
│   │       └── http.proto
│   └── toDoList.proto
└── service
    └── toDoList.go

使用 protoc 生成存根

protoc -I proto \
  --go_out ./pb/todoPb --go_opt paths=source_relative \
  --go-grpc_out ./pb/todoPb --go-grpc_opt paths=source_relative \
  --grpc-gateway_out ./pb/todoPb --grpc-gateway_opt paths=source_relative \
  proto/toDoList.proto
protoc-go-inject-tag -XXX_skip=xorm -input=./pb/todoPb/toDoList.pb.go

执行以上 protoc 命令工具,生成一个 *.gw.pb.go 文件。

创建 grpc-gateway 目录,并创建 main.go 文件,创建 gRPC-Gateway 多路复用器。

func main() {
 ctx := context.Background()
 ctx, cancel := context.WithCancel(ctx)
 defer cancel()
 mux := runtime.NewServeMux()
 opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
 err := pb.RegisterToDoListHandlerFromEndpoint(ctx, mux, grpcServerEndpoint, opts)
 if err != nil {
  log.Fatalf("Fail to register gRPC gateway service endpoint: %v", err)
 }
 if err = http.ListenAndServe(":8080", mux); err != nil {
  log.Fatalf("Could not setup HTTP endpoint: %v", err)
 }
}

完整代码,请参阅 Github。

启动服务

grpc 服务

go run main.go

gRPC-Gateway

go run grpc-gateway/main.go

cURL 测试

curl http://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 时,它会将 JSON 数据解析为 protobuf 消息。然后,它使用解析的 protobuf 消息发出正常的 Go gRPC 客户端请求。

Go gRPC 客户端将 protobuf 结构编码为 protobuf 二进制格式,并将其发送到 gRPC 服务器。gRPC 服务器处理请求并以 protobuf 二进制格式返回响应。

Go gRPC 客户端将其解析为 protobuf 消息,并将其返回到 gRPC-Gateway,后者将 protobuf 消息编码为 JSON 并将其返回到原始客户端。

图片来自 gRPC-Gateway 官方文档

推荐阅读:

Golang 语言 gRPC 怎么使用?

参考资料:

https://github.com/grpc-ecosystem/grpc-gateway 

https://github.com/googleapis/googleapis 

https://github.com/googleapis/googleapis.github.io/ 


目录
相关文章
|
4月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
277 1
|
10月前
|
中间件 Go
Golang | Gin:net/http与Gin启动web服务的简单比较
总的来说,`net/http`和 `Gin`都是优秀的库,它们各有优缺点。你应该根据你的需求和经验来选择最适合你的工具。希望这个比较可以帮助你做出决策。
513 35
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
711 4
Golang语言之管道channel快速入门篇
|
Go
Golang语言之gRPC程序设计示例
这篇文章是关于Golang语言使用gRPC进行程序设计的详细教程,涵盖了RPC协议的介绍、gRPC环境的搭建、Protocol Buffers的使用、gRPC服务的编写和通信示例。
607 3
Golang语言之gRPC程序设计示例
|
网络协议 安全 Go
Go语言进行网络编程可以通过**使用TCP/IP协议栈、并发模型、HTTP协议等**方式
【10月更文挑战第28天】Go语言进行网络编程可以通过**使用TCP/IP协议栈、并发模型、HTTP协议等**方式
290 13
|
Prometheus Cloud Native Go
Golang语言之Prometheus的日志模块使用案例
这篇文章是关于如何在Golang语言项目中使用Prometheus的日志模块的案例,包括源代码编写、编译和测试步骤。
307 4
Golang语言之Prometheus的日志模块使用案例
|
前端开发 中间件 Go
实践Golang语言N层应用架构
【10月更文挑战第2天】本文介绍了如何在Go语言中使用Gin框架实现N层体系结构,借鉴了J2EE平台的多层分布式应用程序模型。文章首先概述了N层体系结构的基本概念,接着详细列出了Go语言中对应的构件名称,包括前端框架(如Vue.js、React)、Gin的处理函数和中间件、依赖注入和配置管理、会话管理和ORM库(如gorm或ent)。最后,提供了具体的代码示例,展示了如何实现HTTP请求处理、会话管理和数据库操作。
274 1
|
Java Spring
spring cloud gateway在使用 zookeeper 注册中心时,配置https 进行服务转发
spring cloud gateway在使用 zookeeper 注册中心时,配置https 进行服务转发
511 3
|
域名解析 网络协议 应用服务中间件
阿里云服务器配置免费https服务
阿里云服务器配置免费https服务
|
应用服务中间件 网络安全 nginx
配置nginx文件服务器,使用自签名ssl证书发布https服务
配置nginx文件服务器: 1、解压nginx压缩包到指定位置,进入文件夹,打开命令行窗口:执行命令 ``` ./nginx -V ``` 查看nginx版本信息; 如果有显示-with-http_ssl_module表示已编译openssl,支持安装ssl.
781 1
配置nginx文件服务器,使用自签名ssl证书发布https服务

热门文章

最新文章

推荐镜像

更多