golang:REST接口

《GO语言高级编程》设计中案例,仅作为笔记进行收藏。gRPC服务一般用于集群内部通信,如果需要对外暴露服务一般会提供等价的REST接口。通过REST接口比较方便前端JavaScript和后端交互。开源社区中的grpcgateway项目就实现了将gRPC服务转为REST服务的能力。

grpc-gateway的工作原理如下图:

golang:REST接口_第1张图片

通过在Protobuf文件中添加路由相关的元信息,通过自定义的代码插件生成路由相关的处理代码,最终将REST请求转给更后端的gRPC服务处理。

1.环境准备

google/api/annotations.proto  采用 https://github.com/googleapis/googleapis 代替

go get -u github.com/grpc-ecosystem/grpc-gateway/tree/master/protoc-gen-grpc-gateway

go get -u github.com/grpc-ecosystem/grpc-gateway/tree/master/protoc-gen-swagger

go get -u github.com/swagger-api/swagger-ui

2.helloworld.proto

syntax = "proto3";

package main;

import "google/api/annotations.proto";

message StringMessage{
  string value=1;
}

service RestService{
  rpc Get(StringMessage) returns(StringMessage){
    option(google.api.http)={
      get:"/get/{value}"
    };
  }

  rpc Post(StringMessage) returns(StringMessage){
    option(google.api.http)={
      post:"/post"
      body:"*"
    };
  }
}

3.通过插件生成grpc-gateway的路由处理代码

protoc 
	--proto_path=. 
	--proto_path=%GOPATH%github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis 
	--go_out=plugins=grpc:.  helloworld.proto

protoc 
	--proto_path=. 
	--proto_path=%GOPATH%github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis
	--grpc-gateway_out=.  helloworld.proto

4.生成Swagger格式文件用于描述REST接口

protoc 
	--proto_path=. 
	--proto_path=%GOPATH%github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis
	--swagger_out=.  helloworld.proto

5.main.go

package main

import (
	"flag"
	"log"
	"net"
	"net/http"

	"github.com/golang/glog"
	"github.com/grpc-ecosystem/grpc-gateway/runtime"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

var (
	port = ":5000"
	echoEndpoint=flag.String("echo_endpoint","localhost"+port,"endpoint of YourService")
)

type myGrpcServer struct {}

func(s *myGrpcServer) Get(ctx context.Context,in *StringMessage)(*StringMessage,error){
	return &StringMessage{Value: "Get:"+in.Value},nil
}

func(s *myGrpcServer) Post(ctx context.Context,in *StringMessage)(*StringMessage,error){
	return &StringMessage{Value: "Post: "+in.Value},nil
}

func run() error{
	ctx:=context.Background()
	ctx,cancel:=context.WithCancel(ctx)
	defer cancel()

	// 创建路由处理器
	mux:=runtime.NewServeMux()
	opts:=[]grpc.DialOption{grpc.WithInsecure()}
	// 将RestService服务相关的REST接口转到后面的gRPC服务
	err:=RegisterRestServiceHandlerFromEndpoint(ctx,mux,*echoEndpoint,opts)
	if err!=nil{
		return err
	}

	return http.ListenAndServe(":8080",mux)
}

func main(){
	flag.Parse()
	defer glog.Flush()

	go startGrpcServer()

	if err := run(); err != nil {
		glog.Fatal(err)
	}
}

func startGrpcServer(){
	server:=grpc.NewServer()
	RegisterRestServiceServer(server,new(myGrpcServer))

	lis,err:=net.Listen("tcp",port)
	if err != nil {
		log.Panicf("could not list on %s: %s", port, err)
	}

	if err := server.Serve(lis); err != nil {
		log.Panicf("grpc serve error: %s", err)
	}

}

6.执行

curl localhost:8080/get/gopher  // {"value":"Get: gopher"}

curl localhost:8080/post -X POST --data '{"value":"grpc"}' // {"value":"Post: grpc"}

7.Swagger-ui

从 swagger-ui库中将 dist 文件夹移到自己的项目中,并更名为swagger。把swagger>>index.html中 url 进行更改。

项目路径如下:

golang:REST接口_第2张图片

在main中添加代码如下:

func run() error{
	ctx:=context.Background()
	ctx,cancel:=context.WithCancel(ctx)
	defer cancel()

	// 创建路由处理器
	mux:=runtime.NewServeMux()
	opts:=[]grpc.DialOption{grpc.WithInsecure()}
	// 将RestService服务相关的REST接口转到后面的gRPC服务
	err:=RegisterRestServiceHandlerFromEndpoint(ctx,mux,*echoEndpoint,opts)
	if err!=nil{
		return err
	}

	http.Handle("/swagger/", http.StripPrefix("/swagger/", http.FileServer(http.Dir("swagger"))))

	return http.ListenAndServe(":8080",mux)
}

8.项目运行

添加过 swagger 代码后,发现不出现效果,正常的 curl 测试还是可以的。

curl localhost:8080/get/gopher
{"value":"Get: gopher"}

curl localhost:8080/post -X POST --data '{"value":"grpc"}'
{"value":"Post: grpc"}

经研究,http.ListenAndServe 采用默认 handle 时可以正常运行,但是接口无法访问。

func run() error{
	ctx:=context.Background()
	ctx,cancel:=context.WithCancel(ctx)
	defer cancel()

	// 创建路由处理器
	mux:=runtime.NewServeMux()
	opts:=[]grpc.DialOption{grpc.WithInsecure()}
	// 将RestService服务相关的REST接口转到后面的gRPC服务
	err:=RegisterRestServiceHandlerFromEndpoint(ctx,mux,*echoEndpoint,opts)
	if err!=nil{
		return err
	}

	http.Handle("/swagger/", http.StripPrefix("/swagger/", http.FileServer(http.Dir("swagger"))))

	return http.ListenAndServe(":8080",nil)
}

根据现在掌握的暂时无法解决,各位如果有解决的办法,请在评论区留言,谢过。

 

 

 

 

 

 

 

你可能感兴趣的:(golang)