这个例子展示了 go-micro/service/grpc 的使用方法。
目录 greeter -- 问候 微服务
目录 gateway -- grpc 网关
创建 micro.Service : service := grpc.NewService()
What if you want to add grpc to a pre-existing service? Use the build pattern for plugins but swap out the client/server.???
目录如下:
greeter/srv/proto/hello/hello.proto
syntax = "proto3";
package greeter;
service Say {
rpc Hello(Request) returns (Response) {}
}
message Request {
string name = 1;
}
message Response {
string msg = 1;
}
使用protoc 工具 创建 hello.pb.go ; hello.micro.go;
bogon:grpc zhaozhiliang$ protoc --proto_path=$GOPATH/src:. --micro_out=. --go_out=. greeter/srv/proto/hello.proto
greeter/srv/main.go 代码如下:
package main
import (
"context"
"github.com/micro/go-micro"
"github.com/micro/go-micro/service/grpc"
"log"
"time"
"zhaozhiliang.com/grpc/greeter/srv/proto/hello"
)
type Say struct{}
func (s *Say) Hello(ctx context.Context, req *hello.Request, rsp *hello.Response) (err error) {
log.Print("Received Say.Hello request")
rsp.Msg = "Hello " + req.Name
return
}
func main() {
service := grpc.NewService(
micro.Name("greeter"),
micro.RegisterTTL(time.Second*30),
micro.RegisterInterval(time.Second*10),
)
// optionally setup command line usage
service.Init()
// Register Handlers
hello.RegisterSayHandler(service.Server(), new(Say))
// Run server
if err := service.Run(); err != nil {
log.Fatal(err)
}
}
greeter/cli/main.go grpc客户端代码
package main
import (
"context"
"fmt"
"github.com/micro/go-micro/metadata"
"github.com/micro/go-micro/service/grpc"
"zhaozhiliang.com/grpc/greeter/srv/proto/hello"
)
func main() {
service := grpc.NewService()
service.Init()
//使用 生成的 client
//如果有 多个服务 怎么创建 cl
cl := hello.NewSayService("greeter", service.Client())
//在 context 中设置 任意的 头信息
ctx := metadata.NewContext(context.Background(), map[string]string{
"X-User-Id" : "john",
"X-From-Id" : "script",
})
//不用指定端口就可以 调用服务了,服务端使用了 服务注册?
rsp, err := cl.Hello(ctx, &hello.Request{
Name : "Liang",
})
if err != nil {
fmt.Println(err)
return
}
fmt.Println(rsp.Msg)
}
运行服务:
bogon:greeter zhaozhiliang$ go run srv/main.go --registry=mdns
ld: warning: object file (/var/folders/np/kffm4b517r57z3gsd7_py49w0000gn/T/go-link-264028127/000017.o) was built for newer OSX version (10.15) than being linked (10.13)
ld: warning: object file (/var/folders/np/kffm4b517r57z3gsd7_py49w0000gn/T/go-link-264028127/go.o) was built for newer OSX version (10.15) than being linked (10.13)
2020-01-06 16:19:09.288398 I | Server [grpc] Listening on [::]:56408
2020-01-06 16:19:09.288526 I | Broker [http] Connected to [::]:56409
2020-01-06 16:19:09.288894 I | Registering node: greeter-626f0229-a84a-4240-b1a2-09112dbd11cc
2020-01-06 16:20:19.915843 I | Received Say.Hello request
测试服务:
bogon:greeter zhaozhiliang$ go run cli/main.go --registry=mdns
# command-line-arguments
ld: warning: object file (/var/folders/np/kffm4b517r57z3gsd7_py49w0000gn/T/go-link-899183069/000000.o) was built for newer OSX version (10.15) than being linked (10.13)
Hello Liang
bogon:greeter zhaozhiliang$
网关相关代码如下:
gateway/proto/hello/hello.proto
syntax = "proto3";
package greeter;
import "google/api/annotations.proto";
service Say {
rpc Hello(Request) returns (Response) {
option (google.api.http) = {
post : "/greeter/hello"
body: "*"
};
}
}
message Request {
string name = 1;
}
message Response {
string msg = 1;
}
通过下面的proto命令生成grpc的存根和反向代理
protoc -I/usr/local/include -I. \
-I$GOPATH/src \
-I$GOPATH/pkg/mod/github.com/grpc-ecosystem/grpc-gateway\@v1.12.1/third_party/googleapis \
--go_out=plugins=grpc:. \
hello/hello.proto
protoc -I/usr/local/include -I. \
-I$GOPATH/src \
-I$GOPATH/pkg/mod/github.com/grpc-ecosystem/grpc-gateway\@v1.12.1/third_party/googleapis \
--grpc-gateway_out=logtostderr=true:. \
hello/hello.proto
greeter/main.go 网关代码如下:
package main
import (
"context"
"flag"
"github.com/golang/glog"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"google.golang.org/grpc"
"net/http"
"zhaozhiliang.com/grpc/gateway/proto/hello"
)
var (
// greeter service address
endpoint = flag.String("endpoint", "localhost:9090", "greeter service address")
)
func run() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
err := greeter.RegisterSayHandlerFromEndpoint(ctx, mux, *endpoint, opts)
if err != nil {
return err
}
return http.ListenAndServe(":8080", mux)
}
func main() {
flag.Parse()
defer glog.Flush()
if err := run(); err != nil {
glog.Fatal(err)
}
}
使用:
1. 运行 greeter service
go run ../greeter/srv/main.go --server_address=localhost:9090
2. 运行网关:
go run main.go
3. curl 方式请求 网关(localhost:8080)
curl -d '{"name": "john"}' http://localhost:8080/greeter/hello
bogon:greeter zhaozhiliang$ curl -d '{"name": "john"}' http://localhost:8080/greeter/hello
{"msg":"Hello john"}bogon:greeter zhaozhiliang$ curl -d '{"name": "john"}' http://localhost:8080/greeter/hello
{"error":"connection error: desc = \"transport: Error while dialing dial tcp [::1]:9090: connect: connection refused\"","code":14,"message":"connection error: desc = \"transport: Error while dialing dial tcp [::1]:9090: connect: connection refused\""}bogon:greeter zhaozhiliang$ curl -d '{"name": "john"}' http://localhost:8080/greeter/hello
{"msg":"Hello john"}bogon:greeter zhaozhiliang$
本例子使用到的模块:
go.mod 文件内容如下:
module zhaozhiliang.com/grpc
go 1.13
require (
github.com/golang/protobuf v1.3.2
github.com/grpc-ecosystem/grpc-gateway v1.12.1
github.com/micro/go-micro v1.18.0
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb
google.golang.org/grpc v1.26.0
)