gRPC之gateway集成swagger

1、gateway集成swagger

1、为了简化实战过程,gRPC-Gateway暴露的服务并未使用https,而是http,但是swagger-ui提供的调用服

务却是https的,因此要在proto文件中指定swaggerhttp调用服务,指定的时候会用到文件

protoc-gen-swagger/options/annotations.proto,因此需要找到这个文件对应的包,放在合适的位置。

2、swaggerdemo.swagger.json:这是swagger-ui要用的json文件,依据此文件,swagger才能正确的展现

gRPC-Gateway暴露的服务和参数定义,可以在页面上发起请求,此文件由插件protoc-gen-swagger生成。

3、在gRPC-Gateway的代码中集成swagger-ui的代码:swagger-ui的代码由多个png、html、js文件组成,

需要用工具go-bindata转换成go源码并放入合适的位置,流程如下图:

在这里插入图片描述

4、要将swaggerdemo.swagger.json文件通过web暴露出来,需要工具go-bindata-assetfs

5、使用swagger的方式:打开swagger-ui页面后,将swaggerdemo.swagger.json输入给swagger-ui页面,

令其解析后,生成对应的在线接口服务。

1.1 安装必要的go包

1、安装protoc-gen-swagger

$ go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
$ go install github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger

2、go-bindata用来将swagger-ui的源码转为GO代码:

$ go install github.com/jteeuwen/go-bindata/...

3、go-bindata-assetfs在应用启动后,对外提供文件服务,这样可以通过web访问swaggerjson文件:

$ go install github.com/elazarl/go-bindata-assetfs/...

4、glog是常用的日志工具:

$ go get -u github.com/golang/glog

1.2 编写proto文件

新建swaggerdemo.proto

// 协议类型
syntax = "proto3";// 包名
package swaggerdemo;option go_package="./protoc;swaggerdemo";import "google/api/annotations.proto";
import "protoc-gen-swagger/options/annotations.proto";// 定义swagger内容
option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {info: {title: "grpc gateway helloworld sample";version: "1.0";};schemes: HTTP;
};// 定义的服务名
service Greeter {// 具体的远程服务方法rpc SayHello (HelloRequest) returns (HelloReply) {option (google.api.http) = {post: "/helloworld"body: "*"};}
}// SayHello方法的入参,只有一个字符串字段
message HelloRequest {string name = 1;
}// SayHello方法的返回值,只有一个字符串字段
message HelloReply {string message = 1;
}

protoc-gen-swagger/options/annotations.proto来自于:

github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger

生成swaggerdemo.pb.go,gRPC所需的go文件:

$ protoc --go_out=plugins=grpc:. protoc/swaggerdemo.proto

生成swaggerdemo.pb.gw.go,gRPC-Gateway所需的go文件:

$ protoc --grpc-gateway_out=logtostderr=true:. protoc/swaggerdemo.proto

生成swaggerdemo.swagger.jsonswagger-ui要用的json文件,依据此文件,swagger展现的页面中会有

gRPC-Gateway暴露的服务和参数定义,可以在页面上发起请求:

$ protoc --swagger_out=logtostderr=true:. protoc/swaggerdemo.proto

1.3 生成swagger-ui的go文件

https://github.com/swagger-api/swagger-ui下载包,解压把dist目录下的所有文件拷贝我们项目的

/swagger/swagger-ui/目录下。

运行指令把Swagger UI转成datafile.go代码:

$ go-bindata --nocompress -pkg swagger -o swagger/datafile.go swagger/swagger-ui/...

1.4 编写gRPC的服务端代码

新建文件server.go,内容如下:

package mainimport ("context""google.golang.org/grpc""log""net"pb "swaggerproject/protoc"
)const (port = ":50051"
)// 定义结构体,在调用注册api的时候作为入参,
// 该结构体会带上SayHello方法,里面是业务代码
// 这样远程调用时就执行了业务代码了
type server struct {// pb.go中自动生成的,是个空结构体pb.UnimplementedGreeterServer
}// 业务代码在此写,客户端远程调用SayHello时,
// 会执行这里的代码
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {// 打印请求参数log.Printf("Received: %v", in.GetName())// 实例化结构体HelloReply,作为返回值return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}func main() {// 要监听的协议和端口lis, err := net.Listen("tcp", port)if err != nil {log.Fatalf("failed to listen: %v", err)}// 实例化gRPC server结构体s := grpc.NewServer()// 服务注册pb.RegisterGreeterServer(s, &server{})log.Println("开始监听,等待远程调用...")if err := s.Serve(lis); err != nil {log.Fatalf("failed to serve: %v", err)}
}

1.5 编写gRPC-Gateway服务端的代码

新建文件gateway.go,内容如下:

package mainimport ("github.com/golang/glog""github.com/grpc-ecosystem/grpc-gateway/runtime""golang.org/x/net/context""google.golang.org/grpc""log""net/http""path""strings"gw "swaggerproject/protoc""swaggerproject/swagger"assetfs "github.com/elazarl/go-bindata-assetfs"
)func run() error {ctx := context.Background()ctx, cancel := context.WithCancel(ctx)defer cancel()gwmux, err := newGateway(ctx)if err != nil {panic(err)}mux := http.NewServeMux()mux.Handle("/", gwmux)mux.HandleFunc("/swagger/", serveSwaggerFile)serveSwaggerUI(mux)log.Println("grpc-gateway listen on localhost:9090")return http.ListenAndServe(":9090", mux)
}func newGateway(ctx context.Context) (http.Handler, error) {opts := []grpc.DialOption{grpc.WithInsecure()}gwmux := runtime.NewServeMux()if err := gw.RegisterGreeterHandlerFromEndpoint(ctx, gwmux, ":50051", opts); err != nil {return nil, err}return gwmux, nil
}func serveSwaggerFile(w http.ResponseWriter, r *http.Request) {log.Println("start serveSwaggerFile")if !strings.HasSuffix(r.URL.Path, "swagger.json") {log.Printf("Not Found: %s", r.URL.Path)http.NotFound(w, r)return}p := strings.TrimPrefix(r.URL.Path, "/swagger/")p = path.Join("./protoc/", p)log.Printf("Serving swagger-file: %s", p)http.ServeFile(w, r, p)
}func serveSwaggerUI(mux *http.ServeMux) {fileServer := http.FileServer(&assetfs.AssetFS{Asset:    swagger.Asset,AssetDir: swagger.AssetDir,Prefix:   "swagger/swagger-ui",})prefix := "/swagger-ui/"mux.Handle(prefix, http.StripPrefix(prefix, fileServer))
}func main() {defer glog.Flush()if err := run(); err != nil {glog.Fatal(err)}
}

对于这个gateway.go文件,有以下几处需要重点注意:

1、外部的RESTful请求转发到server.go的功能,被封装到newGateway方法中;

2、请求URL中如果含有/swagger,就交给serveSwaggerFile方法处理,这里面的逻辑是将文件

swaggerdemo.swagger.json返回给请求方;

3、重点关注serveSwaggerUI方法,经过该方法的处理后,如果请求URL中含有/swagger-ui,就会交给前面

生成的datafile.go处理,也就是打开了swagger-ui的页面;

至此,开发工作已经完成,可以开始验证了。

1.6 测试

[root@zsx swagger_demo]# go run server.go
2023/02/12 19:00:16 开始监听,等待远程调用...[root@zsx swagger_demo]# go run gateway.go
2023/02/12 19:00:28 grpc-gateway listen on localhost:9090

访问 http://127.0.0.1:9090/swagger-ui/

在这里插入图片描述

输入 http://127.0.0.1:9090/swagger/swaggerdemo.swagger.json

在这里插入图片描述

输入请求数据:

在这里插入图片描述

发送请求:

在这里插入图片描述

至此,gateway集成swagger完成。

# 项目结构
$ tree swagger_demo/
swagger_demo/
├── gateway.go
├── go.mod
├── google
│   └── api
│       ├── annotations.proto
│       └── http.proto
├── go.sum
├── protoc
│   ├── swaggerdemo.pb.go
│   ├── swaggerdemo.pb.gw.go
│   ├── swaggerdemo.proto
│   └── swaggerdemo.swagger.json
├── protoc-gen-swagger
│   └── options
│       ├── annotations.proto
│       └── openapiv2.proto
├── server.go
└── swagger├── datafile.go└── swagger-ui├── favicon-16x16.png├── favicon-32x32.png├── index.css├── index.html├── oauth2-redirect.html├── swagger-initializer.js├── swagger-ui-bundle.js├── swagger-ui-bundle.js.map├── swagger-ui.css├── swagger-ui.css.map├── swagger-ui-es-bundle-core.js├── swagger-ui-es-bundle-core.js.map├── swagger-ui-es-bundle.js├── swagger-ui-es-bundle.js.map├── swagger-ui.js├── swagger-ui.js.map├── swagger-ui-standalone-preset.js└── swagger-ui-standalone-preset.js.map7 directories, 31 files

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/117851.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入浅出Dart》函数

函数 Dart语言作为一门面向对象的语言,函数在其中占据了非常重要的位置。本文将详细解析如何定义和调用函数,以及箭头语法,高阶函数和闭包等内容。 1. 函数的定义和调用 在Dart中,函数可以定义为一段实现特定功能的代码块&…

Pytorch使用torchvision.datasets.ImageFolder读取数据集,数据集的内容排列状况

当使用torchvision.datasets.ImageFolder读取猫狗数据集时,dataset中存的图片是 猫狗猫狗猫狗猫狗 还是 猫猫猫猫狗狗狗狗 呢? 数据集文件的存放路径如下图 测试代码如下 import torch import torchvisiontransform torchvision.transforms.Compose([torchvision.transform…

易点易动设备管理系统:提升企业备件管理和维修效率的智能解决方案

在当今竞争激烈的商业环境中,大型生产制造企业面临着日益复杂的设备管理挑战。为了提高生产效率和降低成本,企业需要一种高效的设备管理系统。易点易动设备管理系统是一款智能化的解决方案,旨在帮助企业提升备件管理和维修效率。本文将详细介…

C++笔记之初始化二维矩阵的方法

C笔记之初始化二维矩阵的方法 —— 2023年5月20日 上海 code review! 文章目录 C笔记之初始化二维矩阵的方法一.常见方法1. 使用数组2. 使用向量3. 使用数组的动态分配4. 使用嵌套的 std::vector 并使用resize方法5. 初始化固定大小的 std::array 二.C中使用vector初始化二维矩…

Django token 认证原理与实战

概述 cookie、session 与token 的区别 Cookie的作用 cookie的存储量很小,一般不超过4Kcookie并不会保存很多信息,一般用来存储登录状态cookie是以键值对进行表示的(keyvalue),例如nameli,表示cookie的名字是name,cookie携带的值是licookie的存储分为会…

蓝桥杯双周赛算法心得——摆玩具(分段的差不计入结果)

大家好,我是晴天学长,这是一道可以牢记的数学技巧题。 1) .摆玩具 2) .算法思路 1.创建一个Scanner对象以从用户读取输入。 2.从用户读取n和k的值,分别表示数组的大小和k的值。 3.创建一个大小为n的整数数组a,用于存储输入的数…

Django实现音乐网站 (22)

使用Python Django框架做一个音乐网站, 本篇音乐播放器功能完善:顺序播放、设置播放数、歌词滚动等功能。 目录 顺序播放 设置顺序播放 单曲播放数 添加路由 视图处理 模板处理 歌词滚动 视图内容返回修改 样式设置 模板内容 歌词滚动脚本 歌…

uniapp开发小程序—根据生日日期计算年龄 周岁

0、需求 在UniApp开发小程序中,将接口返回的出生日期转化为年龄;判断接口返回的年龄是否是周岁 可以使用JavaScript的日期处理方法来实现。 一、第一种方式(示例代码): //javascript // 假设接口返回的年龄为生日的…

TCP通信实战案例-即时通信

即时通信是什么含义,要实现怎么样的设计? 即时通信,是指一个客户端的消息发出去,其他客户端可以接收到。 即时通信需要进行端口转发的设计思想。 服务端需要把在线的Socket管道存储起来。 一旦收到一个消息要推送给其他管道。…

Json字符串转换小工具

下载【免费】Json字符串格式化和压缩,支持数组元素的不换行且能转换成16进制资源-CSDN文库 推荐理由: 离线使用支持json字符串的数据格式化和压缩,如:图1支持数组元素的16进制转换,如:图2支持数组元素不换…

小主机折腾记18

这个月冲动消费了小两千块钱…… 1.880g5twr 由于四根2400t的内存条没有用出去,我又把它们装回了惠普的800g5twr; 看到pdd有400块钱的9350K,于是想着给他上一个9350k 在参考了pdd、咸鱼以及淘宝的价格后,我发现400块钱的9350k都…

Autojs 利用OpenCV识别棋子之天天象棋你马没了

本例子通过代码像你介绍利用OpenCV实现霍尔找圆的方法定位棋子位置 通过autojs脚本实现自动点击棋子 开源地址 https://github.com/Liberations/TtxqYourHorseIsGone/blob/master/main.js AutoXJs https://github.com/kkevsekk1/AutoX/releasesauto() //安卓版本高于Android 9…

Plex踩坑——plex web无法找到媒体服务器

现象:之前安装过plex server,然后卸载了。再次重装后,plex web无法找到媒体服务器。 原因:卸载plex server时需要手动将plex的注册表删除:HKEY_CURRENT_USER\Software\Plex, Inc. 原文链接Uninstall Plex Media Serve…

wf-docker集群搭建(未完结)

系列文章目录 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、redis集群二、mysql集群三、nacos集群1. 环境要求2. 拉取镜像2.1. 拉取镜像方式配置集群2.2. 自定义nacos镜像配置集群 3 自定义…

C语言 sizeof 函数内部进行计算

直接看代码 #include <stdio.h> int main() {int i 2;int j;j sizeof(i i);printf("i %d, j %d", i ,j);return 0; }执行结果&#xff1a; 可以看到 i的值一直是没有变的&#xff0c; j 是int类型下 sizeof占用的大小为 4个字节&#xff0c;不是i的 22…

NewStarCTF2023week4-More Fast(GC回收)

打开链接&#xff0c;存在很多个类&#xff0c;很明显是php反序列化漏洞利用&#xff0c;需要构造pop链 &#xff0c; 关于pop链构造的详细步骤教学&#xff0c;请参考我之前的博客&#xff0c;真的讲得很详细也容易理解&#xff1a; http://t.csdnimg.cn/wMYNB 如果你是刚接…

代碼隨想錄算法訓練營|第四十五天|1049. 最后一块石头的重量 II、494. 目标和、474.一和零。刷题心得(c++)

目录 讀題 1049. 最后一块石头的重量 II 自己看到题目的第一想法 看完代码随想录之后的想法 494. 目标和 自己看到题目的第一想法 看完代码随想录之后的想法 474.一和零 自己看到题目的第一想法 看完代码随想录之后的想法 1049. 最后一块石头的重量 II - 實作 思路 …

宏电5G RedCap工业智能网关获首个中国移动5G物联网开放实验室5G及轻量化产品能力认证

10月21日&#xff0c;2023世界物联网博览会——中国移动物联网开发者大会暨物联网产业论坛在无锡圆满举行。宏电股份参与中国移动5G物联网开放实验室5G及轻量化产品能力认证成果授牌仪式&#xff0c;并获得认证证书。 此次认证主要对产品功能、产品性能、RedCap网络兼容性进行测…

sw型材利用父子关系找最新特征

利用父子关系可以找到设计树最新的编辑

复习mysql中的事务

一个事务的开始和结尾必须是 start transaction | commit; rollback 事务特性 1.原子性&#xff1a;多个操作打包成一个整体&#xff0c;要么全部执行&#xff0c;要么一个都不执行。 不过这里的“一个都不执行”并不是真正的全不执行&#xff0c;只是看起来与没执行一样。…