.
├── 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
这里特别指定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
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: "*"
};
}
}
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)
}
})
}
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
)