grpc(golang)支持http(gRpc-Gateway)

步骤介绍
  1. 通过openssl生成密钥公钥
  2. 服务端代码,客户端代码
  3. 通过gomod拉取代码所用的库
  4. 编译proto文件,分为两步->go_out
  5. 运行服务端代码
  6. 通过http(post)访问,通过grpc client访问
    官方文档: https://grpc-ecosystem.github.io/grpc-gateway/docs/tutorials/adding_annotations/
目录结构
.
├── Makefile
├── client
│   └── main.go
├── go.mod
├── go.sum
├── keys
│   ├── server.crt
│   └── server.key
├── proto
│   ├── gateway.pb.go
│   ├── gateway.pb.gw.go
│   └── gateway.proto
└── server
    └── main.go
makefile文件

这里特别指定googleapis所在位置

ECOSYSTEM := /pkg/mod/github.com/grpc-ecosystem/grpc-gateway@v1.12.1/third_party/googleapis
GOPATH :=$(shell go env GOPATH)

step_key:
	openssl genrsa -out keys/server.key 2048
step_crt:	
	openssl req -new -x509 -sha256 -key keys/server.key \
 	-out keys/server.crt -days 36500 \
 	-subj /C=CN/ST=xxx/L=xxx/O=xxx/OU=tech/CN=xxx/
 	
step1:
	go mod init grpc_project
step2:
	go mod tidy

# 编译proto生成.pb.go
step3:
	protoc -I. -I${GOPATH}${ECOSYSTEM} --go_out=plugins=grpc:. proto/gateway.proto
# 编译proto生成.pb.gw.go
step4:
	protoc -I. -I${GOPATH}${ECOSYSTEM} --grpc-gateway_out=logtostderr=true:. proto/gateway.proto

step5:
	cd server && go run main.go

step6:
	curl -X POST -k https://localhost:8488/v1/example/echo -d '{"value": " world"}'

step7:
	cd client &&  go run main.go


gateway.proto
syntax = "proto3";
package gateway;


import "google/api/annotations.proto";

message StringMessage {
    string value = 1;
}


service Gateway {
   rpc Echo(StringMessage) returns (StringMessage) {
       option (google.api.http) = {
           post: "/v1/example/echo"
           body: "*"
       };
   }
   rpc Print(StringMessage) returns (StringMessage) {
        option (google.api.http) = {
            post: "/v1/example/echo2"
            body: "*"
        };
    }
}

server/main.go
package main

import (
	"crypto/tls"
	"io/ioutil"
	"net"
	"net/http"
	"strings"

	"github.com/grpc-ecosystem/grpc-gateway/runtime"
	pb "grpc_project/proto"
	"golang.org/x/net/context"
	"golang.org/x/net/http2"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/grpclog"
	"fmt"
)

// 定义helloHTTPService并实现约定的接口
type gatewayServer struct{}


var GatewayServer = gatewayServer{}


func (h gatewayServer) Echo(ctx context.Context, in *pb.StringMessage) (*pb.StringMessage, error) {
	resp := new(pb.StringMessage)
	resp.Value = "Hello " + in.Value + "."
	fmt.Println(resp.Value)
	return resp, nil
}
func (h gatewayServer) Print(ctx context.Context, in *pb.StringMessage) (*pb.StringMessage, error) {
	resp := new(pb.StringMessage)
	resp.Value = "Hello Print" + in.Value + "."

	return resp, nil
}

var  crt string= "../keys/server.crt"
var endpoint = "127.0.0.1:8488"
func main() {
	fmt.Printf("server start : %v\n",endpoint)
	
	conn, err := net.Listen("tcp", endpoint)
	if err != nil {
		grpclog.Fatalf("TCP Listen err:%v\n", err)
	}

	// grpc server
	creds, err := credentials.NewServerTLSFromFile(crt, "../keys/server.key")
	if err != nil {
		grpclog.Fatalf("Failed to create server TLS credentials %v", err)
	}
	s := grpc.NewServer(grpc.Creds(creds))
	pb.RegisterGatewayServer(s, GatewayServer)

	// gw server
	ctx := context.Background()
	dcreds, err := credentials.NewClientTLSFromFile(crt, "xxx")
	if err != nil {
		grpclog.Fatalf("Failed to create client TLS credentials %v", err)
	}
	dopts := []grpc.DialOption{grpc.WithTransportCredentials(dcreds)}
	gwmux := runtime.NewServeMux()
	if err = pb.RegisterGatewayHandlerFromEndpoint(ctx, gwmux, endpoint, dopts); err != nil {
		grpclog.Fatalf("Failed to register gw server: %v\n", err)
	}

	// http服务
	mux := http.NewServeMux()
	mux.Handle("/", gwmux)

	srv := &http.Server{
		Addr:      endpoint,
		Handler:   grpcHandlerFunc(s, mux),
		TLSConfig: getTLSConfig(),
	}

	grpclog.Infof("gRPC and https listen on: %s\n", endpoint)

	if err = srv.Serve(tls.NewListener(conn, srv.TLSConfig)); err != nil {
		grpclog.Fatal("ListenAndServe: ", err)
	}

	return
}

func getTLSConfig() *tls.Config {
	cert, _ := ioutil.ReadFile(crt)
	key, _ := ioutil.ReadFile("../keys/server.key")
	var demoKeyPair *tls.Certificate
	pair, err := tls.X509KeyPair(cert, key)
	if err != nil {
		grpclog.Fatalf("TLS KeyPair err: %v\n", err)
	}
	demoKeyPair = &pair
	return &tls.Config{
		Certificates: []tls.Certificate{*demoKeyPair},
		NextProtos:   []string{http2.NextProtoTLS}, // HTTP2 TLS支持
	}
}

// grpcHandlerFunc returns an http.Handler that delegates to grpcServer on incoming gRPC
// connections or otherHandler otherwise. Copied from cockroachdb.
func grpcHandlerFunc(grpcServer *grpc.Server, otherHandler http.Handler) http.Handler {
	if otherHandler == nil {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			grpcServer.ServeHTTP(w, r)
		})
	}
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
			grpcServer.ServeHTTP(w, r)
		} else {
			otherHandler.ServeHTTP(w, r)
		}
	})
}
client/main.go
package main

import (
	"log"
	"os"
	pb "grpc_project/proto"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
)

func main() {
	creds, err := credentials.NewClientTLSFromFile("../keys/server.crt", "xxx")
	if err != nil {
		panic(err)
	}

	// 建立连接到gRPC服务
	conn, err := grpc.Dial("127.0.0.1:8488", grpc.WithTransportCredentials(creds),)
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	// 函数结束时关闭连接
	defer conn.Close()
	t := pb.NewGatewayClient(conn)
	// 模拟请求数据
	res := "world"
	if len(os.Args) > 1 {
		res = os.Args[1]
	}

	// 调用gRPC接口
	tr, err := t.Echo(context.Background(), &pb.StringMessage{Value: res})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("服务端响应: %s", tr.Value)
}

一个简单demo,再贴一个上面代码使用的相关版本

module grpc_project

go 1.13

require (
	github.com/golang/protobuf v1.4.2
	github.com/grpc-ecosystem/grpc-gateway v1.12.1
	golang.org/x/net v0.0.0-20200707034311-ab3426394381
	google.golang.org/genproto v0.0.0-20200726014623-da3ae01ef02d
	google.golang.org/grpc v1.30.0
)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值