蜂信物联FastBee平台https://gitee.com/beecue/fastbee
阿里资料开源项目https://gitee.com/vip204888
百度低代码前端框架https://gitee.com/baidu/amis
OpenHarmony开源项目https://gitcode.com/openharmony
仓颉编程语言开放项目https://gitcode.com/Cangjie
- 这个git项目中有多个文件夹,本章的应用在go-source文件夹下,如下图红框所示:
- go-source里面有多个子文件夹,本篇的源码在swaggerdemo中,如下图红框:
提前预览关键知识点
在gRPC-Gateway集成swagger服务的过程并不简单,咱们将其中的重点提前看一下,做到心里有数:
-
为了简化实战过程,gRPC-Gateway暴露的服务并未使用https,而是http,但是swagger-ui提供的调用服务却是https的,因此要在proto文件中指定swagger以http调用服务,指定的时候会用到文件protoc-gen-swagger/options/annotations.proto,因此需要找到这个文件对应的包,放在合适的位置;
-
swaggerdemo.swagger.json:这是swagger-ui要用的json文件,依据此文件,swagger才能正确的展现出gRPC-Gateway暴露的服务和参数定义,可以在页面上发起请求,此文件由插件protoc-gen-swagger生成,该插件是上一篇《gRPC-Gateway实战》中安装好的;
-
在gRPC-Gateway的代码中集成swagger-ui的代码:swagger-ui的代码由多个png、html、js文件组成,需要用工具go-bindata转换成go源码并放入合适的位置,流程如下图:
-
要将swaggerdemo.swagger.json文件通过web暴露出来,需要工具go-bindata-assetfs;
-
使用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.map
8 directories, 23 files
新建工程文件夹
- 本次实战与前面几篇文章的代码没有关系,而是一个全新的工程,请在$GOPATH/src下面新建名为swaggerdemo的文件夹;
安装必要的go包
-
安装git,执行命令sudo yum install -y git unzip
-
工程中会用到几个包,接下来逐个安装;
-
go-bindata用来将swagger-ui的源码转为GO代码:
go get -u github.com/jteeuwen/go-bindata/…
- go-bindata-assetfs在应用启动后,对外提供文件服务,这样可以通过web访问swagger的json文件:
go get -u github.com/elazarl/go-bindata-assetfs/…
- 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的内容中,具体的配置有以下两处:
-
用import关键词导入protoc-gen-swagger/options/annotations.proto
-
下面这段就是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目录下新增以下三个文件:
-
swaggerdemo.pb.go:gRPC所需的go文件
-
swaggerdemo.pb.gw.go:gRPC-Gateway所需的go文件
-
swaggerdemo.swagger.json:swagger-ui要用的json文件,依据此文件,swagger展现的页面中会有gRPC-Gateway暴露的服务和参数定义,可以在页面上发起请求
生成swagger-ui的go文件
- 要想在服务中提供swagger的web页面,需要将swagger-ui的源码转为go文件,步骤如下:
-
接下来的命令会从Github下载swagger-ui的源码,这个文件本该从swagger官方下载,但是我这里尝试多次后发现,下载得到的zip包很容器出现文件损坏而无法解压缩的情况,于是我将此文件放在了自己的Github上,下面的操作也是从我自己的Github下载的,但实际上此文件和swagger官方的并无区别;
-
进入目录$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
- 执行以下命令新建文件夹,该文件夹用来存放稍后生成的swagger-ui的go源码:
mkdir -p $GOPATH/src/swaggerdemo/pkg/ui/data/swagger
- 执行以下命令,将swagger-ui源码转为datafile.go文件:
cd $GOPATH/src/swaggerdemo/
go-bindata --nocompress -pkg swagger -o pkg/ui/data/swagger/datafile.go third_party/swagger-ui/…
- 这时候在$GOPATH/src/swaggerdemo/pkg/ui/data/swagger目录下生成了文件datafile.go
- 所有文件和材料已经准备完成,开始编码;
编写gRPC的服务端代码
- 按照swaggerdemo.proto的配置新建一个gRPC服务,步骤如下:
-
新建文件夹$GOPATH/src/swaggerdemo/server;
-
在新建的server文件夹下新增文件server.go,内容如下,只是个普通的gRPC服务而已:
package main
import (
“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)
}
最后
面试是跳槽涨薪最直接有效的方式,马上金九银十来了,各位做好面试造飞机,工作拧螺丝的准备了吗?
掌握了这些知识点,面试时在候选人中又可以夺目不少,暴击9999点。机会都是留给有准备的人,只有充足的准备,才可能让自己可以在候选人中脱颖而出。
rver) 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)
}
最后
面试是跳槽涨薪最直接有效的方式,马上金九银十来了,各位做好面试造飞机,工作拧螺丝的准备了吗?
掌握了这些知识点,面试时在候选人中又可以夺目不少,暴击9999点。机会都是留给有准备的人,只有充足的准备,才可能让自己可以在候选人中脱颖而出。
[外链图片转存中…(img-elM9upUI-1725137994773)]
[外链图片转存中…(img-9vP9AXbI-1725137994774)]