今天從頭到尾用了一下go的grpc,對grpc鑑權,Deadlines,反射等相關知識有了新的認識
先是部署了kong,建立了services,routes,轉發到go的grpc端口進行測試.
真幸運,10天前安裝的kong還不支持GRPC,前幾天竟然發佈了新版對GRPC做了支持..
有空整理一下使用kong連GRPC的一些坑~~
所連接的IP地址是kong的.如果你沒有安裝kong直接連接go的grpc端即可.
1,proto文件
新建proto文件
syntax = "proto3";
//生成go文件
//protoc --go_out=plugins=grpc:. *.proto
package hello;
service HelloService {
rpc Fun1 (Request) returns (Response);
rpc Fun2 (Request) returns (Response);
}
message Request {
string name = 1;
}
message Response{
string message =1;
}
client端代碼
package main
import (
"context"
"flag"
"fmt"
"go-demo/grpc/proto/hello"
"google.golang.org/grpc"
"time"
)
//go run client/hello/main.go -addr=127.0.0.1:5001 -name=asdfasdf
var addr = flag.String("addr", "127.0.0.1:9080", "register address")
var name = flag.String("name", "duzhenxun", "要發送的名稱")
func main() {
flag.Parse()
auth := Authentication{
appKey: "duzhenxun",
appSecret: "password",
}
conn, err := grpc.Dial(*addr, grpc.WithInsecure(), grpc.WithPerRPCCredentials(&auth))
if err != nil {
//log.Fatal(err)
}
defer conn.Close()
//使用服務
client := hello.NewHelloServiceClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
defer cancel()
r, err := client.Fun1(ctx, &hello.Request{Name: *name})
if err != nil {
fmt.Printf("%v %s\n", time.Now().Format("2006-01-02 15:04:05"), err.Error())
}
fmt.Printf("%v %s\n", time.Now().Format("2006-01-02 15:04:05"), r.Message)
//無需認證
r2, err := client.Fun2(ctx, &hello.Request{Name: *name})
if err != nil {
fmt.Printf("%v %s\n", time.Now().Format("2006-01-02 15:04:05"), err.Error())
}
fmt.Printf("%v %s\n", time.Now().Format("2006-01-02 15:04:05"), r2.Message)
//循環請求
ticker := time.NewTicker(time.Second * 2)
for range ticker.C {
client := hello.NewHelloServiceClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
defer cancel()
r, _ := client.Fun1(ctx, &hello.Request{Name: *name})
fmt.Printf("%v %s\n", time.Now().Format("2006-01-02 15:04:05"), r.Message)
}
}
type Authentication struct {
appKey string
appSecret string
}
func (a *Authentication) GetRequestMetadata(context.Context, ...string) (
map[string]string, error,
) {
return map[string]string{"app_key": a.appKey, "app_secret": a.appSecret}, nil
}
func (a *Authentication) RequireTransportSecurity() bool {
return false
}
server 代碼
package main
import (
"context"
"errors"
"flag"
"fmt"
"go-demo/grpc/proto/hello"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/grpc/reflection"
"log"
"net"
)
var (
port = flag.Int("port", 5000, "listening port")
)
func main() {
//解析傳入參數
flag.Parse()
//註冊可用服務,服務中的fun1需要token驗證,fun2可以直接訪問
grpcServer := grpc.NewServer()
hello.RegisterHelloServiceServer(grpcServer, &helloService{})
//監聽端口
log.Printf("starting service at %d", *port)
lis, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", *port))
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
// Register reflection service on gRPC server.
reflection.Register(grpcServer)
grpcServer.Serve(lis)
}
// used to implement hello.HelloServiceServer.
type helloService struct {
}
//需要token認證
func (this *helloService) Fun1(ctx context.Context, in *hello.Request) (*hello.Response, error) {
auth := Auth{}
if err := auth.Check(ctx); err != nil {
return &hello.Response{Message: err.Error()}, nil
}
//設置時間防止客戶端已斷開,服務端還在傻傻的執行
//https://book.eddycjy.com/golang/grpc/deadlines.html
if ctx.Err()==context.Canceled{
return nil, errors.New("客戶端已斷開")
}
fmt.Printf("fun1 name:%v\n",in.Name)
return &hello.Response{Message: "fun1 hello " + in.Name}, nil
}
//直接可以訪問
func (this *helloService) Fun2(ctx context.Context, in *hello.Request) (*hello.Response, error) {
fmt.Printf("fun2 name:%v\n",in.Name)
return &hello.Response{Message: "fun2 hello " + in.Name}, nil
}
type Auth struct {
appKey string
appSecret string
}
func (a *Auth) Check(ctx context.Context) error {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return status.Errorf(codes.Unauthenticated, "metadata.FromIncomingContext err")
}
var (
appKey string
appSecret string
)
if value, ok := md["app_key"]; ok {
appKey = value[0]
}
if value, ok := md["app_secret"]; ok {
appSecret = value[0]
}
if appKey != a.GetAppKey() || appSecret != a.GetAppSecret() {
return errors.New("Token有誤!")
}
return nil
}
func (a *Auth) GetAppKey() string {
return "duzhenxun"
}
func (a *Auth) GetAppSecret() string {
return "password"
}
➜ ~ grpcurl -plaintext 127.0.0.1:9080 list
grpc.reflection.v1alpha.ServerReflection
hello.HelloService
➜ ~ grpcurl -plaintext 127.0.0.1:9080 list hello.HelloService
hello.HelloService.Fun1
hello.HelloService.Fun2
➜ ~ grpcurl -plaintext 127.0.0.1:9080 describe hello.HelloService.Fun1
hello.HelloService.Fun1 is a method:
rpc Fun1 ( .hello.Request ) returns ( .hello.Response );
➜ ~ grpcurl -plaintext 127.0.0.1:9080 describe hello.Request
hello.Request is a message:
message Request {
string name = 1;
}
➜ ~ grpcurl -plaintext 127.0.0.1:9080 describe hello.HelloService.Fun2
hello.HelloService.Fun2 is a method:
rpc Fun2 ( .hello.Request ) returns ( .hello.Response );
➜ ~ grpcurl -plaintext -d '{"name": "gopher"}' 127.0.0.1:9080 hello.HelloService.Fun1
{
"message": "Token有誤!"
}
➜ ~ grpcurl -plaintext -d '{"name": "gopher"}' 127.0.0.1:9080 hello.HelloService.Fun2
{
"message": "fun2 hello gopher"
}