写点什么

gRPC 学习之六:gRPC-Gateway 集成 swagger

  • 2022 年 4 月 20 日
  • 本文字数:3339 字

    阅读完需:约 11 分钟

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 官方下载,但是我这 Java 开源项目【ali1024.coding.net/public/P7/Java/git】 里尝试多次后发现,下载得到的 zip 包很容器出现文 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》开源 件损坏而无法解压缩的情况,于是我将此文件放在了自己的 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/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 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)


}


// 实例化 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 main


import (


"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)

知其然不知其所以然,大厂常问面试技术如何复习?

1、热门面试题及答案大全


面试前做足功夫,让你面试成功率提升一截,这里一份热门 350 道一线互联网常问面试题及答案助你拿 offer



2、多线程、高并发、缓存入门到实战项目 pdf 书籍





3、文中提到面试题答案整理



4、Java 核心知识面试宝典


覆盖了 JVM 、JAVA 集合、JAVA 多线程并发、JAVA 基础、Spring 原理、微服务、Netty 与 RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB 、Cassandra、设计模式、负载均衡、数据库、一致性算法 、JAVA 算法、数据结构、算法、分布式缓存、Hadoop、Spark、Storm 的大量技术点且讲解的非常深入





用户头像

还未添加个人签名 2022.04.13 加入

还未添加个人简介

评论

发布
暂无评论
gRPC学习之六:gRPC-Gateway集成swagger_Java_爱好编程进阶_InfoQ写作社区