欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

gRPC学习系列文章链接

  1. 在CentOS7部署和设置GO
  2. GO的gRPC开发环境准备
  3. 初试GO版gRPC开发
  4. 实战四类服务方法
  5. gRPC-Gateway实战
  6. gRPC-Gateway集成swagger

本篇概览

  • 本文《gRPC学习》系列的第六篇,前文咱们实战了gRPC-Gateway,将gRPC服务以RESTful形式对外暴露,当时由于篇幅所限没有完成swagger集成,本篇来完成这个工作:开发gRPC服务,为其提供gRPC-Gateway,并提供在线swagger服务;
  • 本文由以下章节构成,这也是gRPC-Gateway集成swagger的常规流程:
  1. 提前预览关键知识点;
  2. 新建工程文件夹;
  3. 安装必要的go包;
  4. 编写proto文件,使swagger支持http(默认是https);
  5. 生成gRPC、gRPC-Gateway所需的go源码;
  6. 生成swagger所需的json文件;
  7. 下载swagger-ui的源码,以此生成go源码;
  8. 编写gRPC的服务端代码;
  9. 编写gRPC-Gateway服务端的代码;
  10. 验证;
  • 注意,本文的所有操作都没有用到root账号,而是前文创建的golang账号;

源码下载

  • 本篇实战中的源码可在GitHub下载到,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):
名称 链接 备注
项目主页 https://github.com/zq2599/blog_demos 该项目在GitHub上的主页
git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本章的应用在go-source文件夹下,如下图红框所示:

  • go-source里面有多个子文件夹,本篇的源码在swaggerdemo中,如下图红框:

提前预览关键知识点

在gRPC-Gateway集成swagger服务的过程并不简单,咱们将其中的重点提前看一下,做到心里有数:

  1. 为了简化实战过程,gRPC-Gateway暴露的服务并未使用https,而是http,但是swagger-ui提供的调用服务却是https的,因此要在proto文件中指定swagger以http调用服务,指定的时候会用到文件protoc-gen-swagger/options/annotations.proto,因此需要找到这个文件对应的包,放在合适的位置;
  2. swaggerdemo.swagger.json:这是swagger-ui要用的json文件,依据此文件,swagger才能正确的展现出gRPC-Gateway暴露的服务和参数定义,可以在页面上发起请求,此文件由插件protoc-gen-swagger生成,该插件是上一篇《gRPC-Gateway实战》中安装好的;
  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页面,令其解析后,生成对应的在线接口服务;

前提条件

  • 本文是 《gRPC-Gateway实战》的续篇,请您参考前文将gRPC-Gateway环境准备好;

提前展示文件结构

  • 本次实战涉及到多个文件,在此先将最终的文件内容全部展示出来,以便您在开发过程中作为参考,所有内容都在$GOPATH/src/swaggerdemo目录下:
[golang@centos7 src]$ tree swaggerdemo/
swaggerdemo/
├── gateway
│   └── gateway.go
├── pkg
│   └── ui
│       └── data
│           └── swagger
│               └── datafile.go
├── server
│   └── server.go
├── swaggerdemo.pb.go
├── swaggerdemo.pb.gw.go
├── swaggerdemo.proto
├── swaggerdemo.swagger.json
└── third_party└── swagger-ui├── favicon-16x16.png├── favicon-32x32.png├── index.html├── oauth2-redirect.html├── 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.map8 directories, 23 files

新建工程文件夹

  • 本次实战与前面几篇文章的代码没有关系,而是一个全新的工程,请在$GOPATH/src下面新建名为swaggerdemo的文件夹;

安装必要的go包

  1. 安装git,执行命令sudo yum install -y git unzip
  2. 工程中会用到几个包,接下来逐个安装;
  3. go-bindata用来将swagger-ui的源码转为GO代码:
go get -u github.com/jteeuwen/go-bindata/...
  1. go-bindata-assetfs在应用启动后,对外提供文件服务,这样可以通过web访问swagger的json文件:
go get -u github.com/elazarl/go-bindata-assetfs/...
  1. glog是常用的日志工具:
go get -u github.com/golang/glog

编写proto文件

  • 进入目录$GOPATH/src/swaggerdemo,新建swaggerdemo.proto,内容如下,有几处要注意的地方稍后会说明:
// 协议类型
syntax = "proto3";// 包名
package 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;
}
  • 文件swaggerdemo.proto和 《gRPC-Gateway实战》一文中的proto文件大部分是一致的,不同之处在于增加了swagger的配置,这个配置的作用是让swagger把远程调用配置成http,如果没有这些配置,swagger默认的远程调用就是https的,本文的gRPC-Gateway提供的是http服务,所以要加上这些配置,在上述swaggerdemo.proto的内容中,具体的配置有以下两处:
  1. 用import关键词导入protoc-gen-swagger/options/annotations.proto
  2. 下面这段就是swagger的配置了,重点是schemes,里面只有HTTP:
option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {info: {title: "grpc gateway helloworld sample";version: "1.0";    };schemes: HTTP;
};
  • 还要把swaggerdemo.proto中提到的protoc-gen-swagger/options/annotations.proto文件放在合适的地方,以便使用swaggerdemo.proto的时候能找到此annotations.proto文件,执行以下命令:
cd $GOPATH/src
cp -r ./github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger ./
  • 上述命令中的protoc-gen-swagger文件夹,是在前文的操作中下载好的;

生成gRPC、gRPC-Gateway所需的go源码

  • 生成gRPC、gRPC-Gateway所需的go源码,这样的操作在前面已经做过,这里用swaggerdemo.proto再做一次,先进入目录$GOPATH/src/swaggerdemo
  • 执行以下命令,生成gRPC所需源码:
protoc -I. \
-I$GOPATH/src \
-I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--go_out=plugins=grpc:. \
swaggerdemo.proto
  • 执行以下命令,生成gRPC-Gateway所需源码:
protoc -I. \
-I$GOPATH/src \
-I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--grpc-gateway_out=logtostderr=true:. \
swaggerdemo.proto

生成swagger所需的json文件

  • 还是在目录$GOPATH/src/swaggerdemo,执行以下命令,生成swagger所需json:
protoc -I. \
-I$GOPATH/src \
-I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--swagger_out=logtostderr=true:. \
swaggerdemo.proto
  • 此时的$GOPATH/src/swaggerdemo目录下新增以下三个文件:
  1. swaggerdemo.pb.go:gRPC所需的go文件
  2. swaggerdemo.pb.gw.go:gRPC-Gateway所需的go文件
  3. swaggerdemo.swagger.json:swagger-ui要用的json文件,依据此文件,swagger展现的页面中会有gRPC-Gateway暴露的服务和参数定义,可以在页面上发起请求

生成swagger-ui的go文件

  • 要想在服务中提供swagger的web页面,需要将swagger-ui的源码转为go文件,步骤如下:
  1. 接下来的命令会从Github下载swagger-ui的源码,这个文件本该从swagger官方下载,但是我这里尝试多次后发现,下载得到的zip包很容器出现文件损坏而无法解压缩的情况,于是我将此文件放在了自己的Github上,下面的操作也是从我自己的Github下载的,但实际上此文件和swagger官方的并无区别;
  2. 进入目录$GOPATH/src/swaggerdemo,执行以下命令下载swagger-ui源码,并放入指定位置:
wget https://raw.githubusercontent.com/zq2599/blog_download_files/master/files/swagger-ui.zip -O swagger-ui.zip \
&& unzip swagger-ui.zip \
&& mkdir -p $GOPATH/src/swaggerdemo/third_party/ \
&& mv ./swagger-ui-3.38.0/dist $GOPATH/src/swaggerdemo/third_party/ \
&& mv $GOPATH/src/swaggerdemo/third_party/dist $GOPATH/src/swaggerdemo/third_party/swagger-ui \
&& rm -f ./swagger-ui.zip \
&& rm -rf ./swagger-ui-3.38.0
  1. 执行以下命令新建文件夹,该文件夹用来存放稍后生成的swagger-ui的go源码:
mkdir -p $GOPATH/src/swaggerdemo/pkg/ui/data/swagger
  1. 执行以下命令,将swagger-ui源码转为datafile.go文件:
cd $GOPATH/src/swaggerdemo/
go-bindata --nocompress -pkg swagger -o pkg/ui/data/swagger/datafile.go third_party/swagger-ui/...
  1. 这时候在$GOPATH/src/swaggerdemo/pkg/ui/data/swagger目录下生成了文件datafile.go
  • 所有文件和材料已经准备完成,开始编码;

编写gRPC的服务端代码

  • 按照swaggerdemo.proto的配置新建一个gRPC服务,步骤如下:
  1. 新建文件夹$GOPATH/src/swaggerdemo/server;
  2. 在新建的server文件夹下新增文件server.go,内容如下,只是个普通的gRPC服务而已:
package mainimport ("context""log""net""google.golang.org/grpc"pb "swaggerdemo"
)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)}
}
  • 以上就是gRPC服务的代码,与前几篇文章中的差不多,就不赘述了;

编写gRPC-Gateway服务端的代码

  • 开始编写gRPC-Gateway服务端代码,这是本文的重点所在,除了提供与前文一样的gRPC-Gateway服务,还提供了swagger的json文件服务,以及swagger的ui服务;
  • 新建文件夹$GOPATH/src/swaggerdemo/gateway;
  • 在新建的gateway文件夹下新增文件gateway.go,内容如下,有几处要注意的地方稍后会说明:
package mainimport ("github.com/elazarl/go-bindata-assetfs""log""net/http""path""strings""github.com/golang/glog""github.com/grpc-ecosystem/grpc-gateway/runtime""golang.org/x/net/context""google.golang.org/grpc"swagger "swaggerdemo/pkg/ui/data/swagger"gw "swaggerdemo"
)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("../", 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:   "third_party/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方法处理,这里面的逻辑是将文件$GOPATH/src/swaggerdemo/swaggerdemo.swagger.json返回给请求方;
  3. 重点关注serveSwaggerUI方法,经过该方法的处理后,如果请求URL中含有/swagger-ui,就会交给前面生成的datafile.go处理,也就是打开了swagger-ui的页面;
  • 至此,开发工作已经完成,可以开始验证了;

验证

  1. 进入目录$GOPATH/src/swaggerdemo/server,执行go run server.go启动gRPC服务;

  2. 进入目录$GOPATH/src/swaggerdemo/gateway,执行go run gateway.go启动gRPC-Gateway服务;

  3. 确保服务所在机器的防火墙已经关闭;

  4. 我这边服务器IP地址是http://192.168.133.204/,因此浏览器访问:http://192.168.133.204:9090/swagger/swaggerdemo.swagger.json ,即可看到swagger.json的内容,如下图:

  5. 访问swagger-ui页面,地址是:http://192.168.133.204:9090/swagger-ui/ ,如下图,可见swagger-ui功能正常:

  6. 此时的swagger-ui页面并未展示gRPC-Gateway的接口内容,需要将http://192.168.133.204:9090/swagger/swaggerdemo.swagger.json填入下图红框1中,再点击红框2的按钮,即可正常展示,红框3就是gRPC-Gateway对外暴露的服务:

  7. 点击下图红框中的Try it out按钮,即可在页面上向后台发起请求:

  8. 如下图,修改红框1中的请求参数,再点击红框2中的按钮,即可发起请求:

  9. 如下图,红框1中是请求地址,可见是http请求,证明咱们之前在proto文件中的设置已经生效,红框2中是收到的返回内容,很明显这个内容来自server.go:

  • 至此,gRPC-Gateway集成swagger的操作就完成了,可见这是一系列繁琐的操作,希望本文能给您提供一些参考,助您顺利集成swagger;

你不孤单,欣宸原创一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列

欢迎关注公众号:程序员欣宸

微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界…

gRPC学习之六:gRPC-Gateway集成swagger相关推荐

  1. 从0到1手把手搭建spring cloud alibaba 微服务大型应用框架(十五) swagger篇 : gateway 集成swagger 与 knife4j实现在线api文档并嵌入到自己项目内

    背景 我们日常开发中基本都是协同开发的,当然极个别的项目整体前后端都是一个人开发的,当多人协作时,尤其是前后端人员协同开发时 必然会面临着前端需要了解后端api接口的情况,两个选择,提前设计好文档,然 ...

  2. gRPC学习与应用(1)

    gRPC学习与应用(1) 一.gRPC简介[1] 1.概述 2.使用Protocol Buffers通信 2.1 数据结构定义 2.2 gRPC服务定义 二.核心概念 1.服务定义 2.同步调用 vs ...

  3. gRPC 学习笔记

    简介 更多内容参考:https://www.grpc.io/docs/guides/ gRPC 是一个高性能.开源和通用的 RPC 框架,面向移动和 HTTP/2 设计.目前提供 C.Java 和 G ...

  4. Go语学习笔记 - grpc server/client protobuf | 从零开始Go语言

    目录 创建Proto文件 生成proto文件对应的go文件 创建服务结构体 创建客户端测试 小结 学习笔记,写到哪是哪. 上一篇是写的redis操作来着,最近主要研究了一下grpc. 在玩grpc的过 ...

  5. 【Python进阶学习】gRPC在Python的异步非阻塞实现方式

    gRPC在Python的异步非阻塞实现方式 前言 问题&分析 问题阐述 原因分析 解决方案 服务端 原服务端实现方式 aio的服务端实现方式: 客户端 异步非阻塞方式 同步阻塞方式 性能优化效 ...

  6. Golang gRPC学习(04): Deadlines超时限制

    为什么要使用Deadlines# 当我们使用gRPC时,gRPC库关系的是连接,序列化,反序列化和超时执行.Deadlines 允许gRPC客户端设置自己等待多长时间来完成rpc操作,直到出现这个错误 ...

  7. gRPC学习Go版(一)

    文章目录 微服务入门 gRPC是什么 proto 服务定义 gRPC 优势 gRPC入门 简单使用 一元RPC 服务流RPC 客户流RPC 双工流RPC gRPC底层原理 RPC流 长度前缀的消息分帧 ...

  8. 深入浅出 gRPC 02:gRPC 客户端创建和调用原理

    目录 1. gRPC 客户端创建流程 1.1 背景 1.2 业务代码示例 1.3 RPC 调用流程 1.3.1 客户端调用总体流程 1.3.2 ManagedChannel 创建流程 1.3.3 Cl ...

  9. Spring Boot 集成 Swagger 生成 RESTful API 文档

    原文链接: Spring Boot 集成 Swagger 生成 RESTful API 文档 简介 Swagger 官网是这么描述它的:The Best APIs are Built with Swa ...

最新文章

  1. 清华大学硕士程序员,纠结选开发还是转算法,烦死了!
  2. 专访北京飞搜科技:一个创业公司该怎样在人工智能大潮中成长
  3. mariadb-10实现半同步复制及SSL安全复制
  4. 测试香港服务器访问速度的方法
  5. Insert Interval
  6. linux 压缩及解压缩 命令
  7. Windows上安装Mac OS虚拟机
  8. bitcount java_Java源码解释之Integer.bitCount
  9. vs2013中对工程、项目和类更名
  10. Blockathon记录——by 参赛者 张翔
  11. Linux-环境变量的设置和查看
  12. 【白皮书分享】2021消费者数智化运营白皮书.pdf(附下载链接)
  13. Oracle存储过程基本语法
  14. 3lcd和dlp怎么选,DLP和3LCD投影机的选择对比
  15. 阿里云服务器部署(2)---配置EMQX服务器(企业版)
  16. shell批量修改后缀_Powershell批量修改用户的UPN后缀
  17. check 和nocheck
  18. 小强升职记梗概_《小强升职记》读书笔记一
  19. 小程序背景图满屏_手机秒变闪屏弹幕,撩妹小程序,赶快来学!
  20. 用Visio绘制switch-case流程图

热门文章

  1. 如何排查开机/重启时间长问题
  2. 福建师范计算机应用基础考试内容,关于印发《福建师范大学 课程教学改革实施方案(试行)》的通知...
  3. linux中umask的原理和作用,Linux 的umask详解
  4. UIButton的selected状态
  5. 找工作时让他先交500元,应聘货车司机竟成搬运工
  6. 华为 荣耀MagicBook 2020 电脑 Hackintosh 黑苹果efi引导文件
  7. 人工智能干货推荐[第1期][06NLP]
  8. 2022全国职业技能大赛“信息安全管理与评估“--应急响应日志分析解析(高职组)
  9. java递增序列号_生成Java自动递增序列号日食
  10. 为什么公司选择裁员,而不是降薪