最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語言程序開發(fā)gRPC服務(wù)

 更新時間:2022年06月15日 15:39:45   作者:yongxinz  
這篇文章主要為大家介紹了Go語言程序開發(fā)gRPC服務(wù),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

gRPC 這項技術(shù)真是太棒了,接口約束嚴(yán)格,性能還高,在 k8s 和很多微服務(wù)框架中都有應(yīng)用。

作為一名程序員,學(xué)就對了。

之前用 Python 寫過一些 gRPC 服務(wù),現(xiàn)在準(zhǔn)備用 Go 來感受一下原汁原味的 gRPC 程序開發(fā)。

本文的特點是直接用代碼說話,通過開箱即用的完整代碼,來介紹 gRPC 的各種使用方法。

代碼已經(jīng)上傳到 GitHub,下面正式開始。

介紹

gRPC 是 Google 公司基于 Protobuf 開發(fā)的跨語言的開源 RPC 框架。gRPC 基于 HTTP/2 協(xié)議設(shè)計,可以基于一個 HTTP/2 鏈接提供多個服務(wù),對于移動設(shè)備更加友好。

入門

首先來看一個最簡單的 gRPC 服務(wù),第一步是定義 proto 文件,因為 gRPC 也是 C/S 架構(gòu),這一步相當(dāng)于明確接口規(guī)范。

proto

syntax?=?"proto3";
package?proto;
//?The?greeting?service?definition.
service?Greeter?{
????//?Sends?a?greeting
????rpc?SayHello?(HelloRequest)?returns?(HelloReply)?{}
}
//?The?request?message?containing?the?user's?name.
message?HelloRequest?{
????string?name?=?1;
}
//?The?response?message?containing?the?greetings
message?HelloReply?{
????string?message?=?1;
}

使用 protoc-gen-go 內(nèi)置的 gRPC 插件生成 gRPC 代碼:

protoc?--go_out=plugins=grpc:.?helloworld.proto

執(zhí)行完這個命令之后,會在當(dāng)前目錄生成一個 helloworld.pb.go 文件,文件中分別定義了服務(wù)端和客戶端的接口:

//?For?semantics?around?ctx?use?and?closing/ending?streaming?RPCs,?please?refer?to?https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type?GreeterClient?interface?{
????//?Sends?a?greeting
????SayHello(ctx?context.Context,?in?*HelloRequest,?opts?...grpc.CallOption)?(*HelloReply,?error)
}
//?GreeterServer?is?the?server?API?for?Greeter?service.
type?GreeterServer?interface?{
????//?Sends?a?greeting
????SayHello(context.Context,?*HelloRequest)?(*HelloReply,?error)
}

接下來就是寫服務(wù)端和客戶端的代碼,分別實現(xiàn)對應(yīng)的接口。

server

package?main
import?(
????"context"
????"fmt"
????"grpc-server/proto"
????"log"
????"net"
????"google.golang.org/grpc"
????"google.golang.org/grpc/reflection"
)
type?greeter?struct?{
}
func?(*greeter)?SayHello(ctx?context.Context,?req?*proto.HelloRequest)?(*proto.HelloReply,?error)?{
????fmt.Println(req)
????reply?:=?&proto.HelloReply{Message:?"hello"}
????return?reply,?nil
}
func?main()?{
????lis,?err?:=?net.Listen("tcp",?":50051")
????if?err?!=?nil?{
????????log.Fatalf("failed?to?listen:?%v",?err)
????}
????server?:=?grpc.NewServer()
????//?注冊?grpcurl?所需的?reflection?服務(wù)
????reflection.Register(server)
????//?注冊業(yè)務(wù)服務(wù)
????proto.RegisterGreeterServer(server,?&greeter{})
????fmt.Println("grpc?server?start?...")
????if?err?:=?server.Serve(lis);?err?!=?nil?{
????????log.Fatalf("failed?to?serve:?%v",?err)
????}
}

client

package?main
import?(
????"context"
????"fmt"
????"grpc-client/proto"
????"log"
????"google.golang.org/grpc"
)
func?main()?{
????conn,?err?:=?grpc.Dial("localhost:50051",?grpc.WithInsecure())
????if?err?!=?nil?{
????????log.Fatal(err)
????}
????defer?conn.Close()
????client?:=?proto.NewGreeterClient(conn)
????reply,?err?:=?client.SayHello(context.Background(),?&proto.HelloRequest{Name:?"zhangsan"})
????if?err?!=?nil?{
????????log.Fatal(err)
????}
????fmt.Println(reply.Message)
}

這樣就完成了最基礎(chǔ)的 gRPC 服務(wù)的開發(fā),接下來我們就在這個「基礎(chǔ)模板」上不斷豐富,學(xué)習(xí)更多特性。

流方式

接下來看看流的方式,顧名思義,數(shù)據(jù)可以源源不斷的發(fā)送和接收。

流的話分單向流和雙向流,這里我們直接通過雙向流來舉例。

proto

service?Greeter?{
????//?Sends?a?greeting
????rpc?SayHello?(HelloRequest)?returns?(HelloReply)?{}
????//?Sends?stream?message
????rpc?SayHelloStream?(stream?HelloRequest)?returns?(stream?HelloReply)?{}
}

增加一個流函數(shù) SayHelloStream,通過 stream 關(guān)鍵詞來指定流特性。

需要重新生成 helloworld.pb.go 文件,這里不再多說。

server

func?(*greeter)?SayHelloStream(stream?proto.Greeter_SayHelloStreamServer)?error?{
????for?{
????????args,?err?:=?stream.Recv()
????????if?err?!=?nil?{
????????????if?err?==?io.EOF?{
????????????????return?nil
????????????}
????????????return?err
????????}
????????fmt.Println("Recv:?"?+?args.Name)
????????reply?:=?&proto.HelloReply{Message:?"hi?"?+?args.Name}
????????err?=?stream.Send(reply)
????????if?err?!=?nil?{
????????????return?err
????????}
????}
}

在「基礎(chǔ)模板」上增加 SayHelloStream 函數(shù),其他都不需要變。

client

client?:=?proto.NewGreeterClient(conn)
//?流處理
stream,?err?:=?client.SayHelloStream(context.Background())
if?err?!=?nil?{
????log.Fatal(err)
}
//?發(fā)送消息
go?func()?{
????for?{
????????if?err?:=?stream.Send(&proto.HelloRequest{Name:?"zhangsan"});?err?!=?nil?{
????????????log.Fatal(err)
????????}
????????time.Sleep(time.Second)
????}
}()
//?接收消息
for?{
????reply,?err?:=?stream.Recv()
????if?err?!=?nil?{
????????if?err?==?io.EOF?{
????????????break
????????}
????????log.Fatal(err)
????}
????fmt.Println(reply.Message)
}

通過一個 goroutine 發(fā)送消息,主程序的 for 循環(huán)接收消息。

執(zhí)行程序會發(fā)現(xiàn),服務(wù)端和客戶端都不斷有打印輸出。

驗證器

接下來是驗證器,這個需求是很自然會想到的,因為涉及到接口之間的請求,那么對參數(shù)進(jìn)行適當(dāng)?shù)男r炇呛苡斜匾摹?/p>

在這里我們使用 protoc-gen-govalidators 和 go-grpc-middleware 來實現(xiàn)。

先安裝:

go?get?github.com/mwitkow/go-proto-validators/protoc-gen-govalidators
go?get?github.com/grpc-ecosystem/go-grpc-middleware

接下來修改 proto 文件:

proto

import?"github.com/mwitkow/go-proto-validators@v0.3.2/validator.proto";
message?HelloRequest?{
????string?name?=?1?[
????????(validator.field)?=?{regex:?"^[z]{2,5}$"}
????];
}

在這里對 name 參數(shù)進(jìn)行校驗,需要符合正則的要求才可以正常請求。

還有其他驗證規(guī)則,比如對數(shù)字大小進(jìn)行驗證等,這里不做過多介紹。

接下來生成 *.pb.go 文件:

protoc??\
????--proto_path=${GOPATH}/pkg/mod?\
????--proto_path=${GOPATH}/pkg/mod/github.com/gogo/protobuf@v1.3.2?\
????--proto_path=.?\
????--govalidators_out=.?--go_out=plugins=grpc:.\
????*.proto

執(zhí)行成功之后,目錄下會多一個 helloworld.validator.pb.go 文件。

這里需要特別注意一下,使用之前的簡單命令是不行的,需要使用多個 proto_path 參數(shù)指定導(dǎo)入 proto 文件的目錄。

官方給了兩種依賴情況,一個是 google protobuf,一個是 gogo protobuf。我這里使用的是第二種。

即使使用上面的命令,也有可能會遇到這個報錯:

Import?"github.com/mwitkow/go-proto-validators/validator.proto"?was?not?found?or?had?errors

但不要慌,大概率是引用路徑的問題,一定要看好自己的安裝版本,以及在 GOPATH 中的具體路徑。

最后是服務(wù)端代碼改造:

引入包:

grpc_middleware?"github.com/grpc-ecosystem/go-grpc-middleware"
grpc_validator?"github.com/grpc-ecosystem/go-grpc-middleware/validator"

然后在初始化的時候增加驗證器功能:

server?:=?grpc.NewServer(
????grpc.UnaryInterceptor(
????????grpc_middleware.ChainUnaryServer(
????????????grpc_validator.UnaryServerInterceptor(),
????????),
????),
????grpc.StreamInterceptor(
????????grpc_middleware.ChainStreamServer(
????????????grpc_validator.StreamServerInterceptor(),
????????),
????),
)

啟動程序之后,我們再用之前的客戶端代碼來請求,會收到報錯:

2021/10/11?18:32:59?rpc?error:?code?=?InvalidArgument?desc?=?invalid?field?Name:?value?'zhangsan'?must?be?a?string?conforming?to?regex?"^[z]{2,5}$"
exit?status?1

因為 name: zhangsan 是不符合服務(wù)端正則要求的,但是如果傳參 name: zzz,就可以正常返回了。

Token 認(rèn)證

終于到認(rèn)證環(huán)節(jié)了,先看 Token 認(rèn)證方式,然后再介紹證書認(rèn)證。

先改造服務(wù)端,有了上文驗證器的經(jīng)驗,那么可以采用同樣的方式,寫一個攔截器,然后在初始化 server 時候注入。

認(rèn)證函數(shù):

func?Auth(ctx?context.Context)?error?{
????md,?ok?:=?metadata.FromIncomingContext(ctx)
????if?!ok?{
????????return?fmt.Errorf("missing?credentials")
????}
????var?user?string
????var?password?string
????if?val,?ok?:=?md["user"];?ok?{
????????user?=?val[0]
????}
????if?val,?ok?:=?md["password"];?ok?{
????????password?=?val[0]
????}
????if?user?!=?"admin"?||?password?!=?"admin"?{
????????return?grpc.Errorf(codes.Unauthenticated,?"invalid?token")
????}
????return?nil
}

metadata.FromIncomingContext 從上下文讀取用戶名和密碼,然后和實際數(shù)據(jù)進(jìn)行比較,判斷是否通過認(rèn)證。

攔截器:

var?authInterceptor?grpc.UnaryServerInterceptor
authInterceptor?=?func(
????ctx?context.Context,?req?interface{},?info?*grpc.UnaryServerInfo,?handler?grpc.UnaryHandler,
)?(resp?interface{},?err?error)?{
????//攔截普通方法請求,驗證?Token
????err?=?Auth(ctx)
????if?err?!=?nil?{
????????return
????}
????//?繼續(xù)處理請求
????return?handler(ctx,?req)
}

初始化:

server?:=?grpc.NewServer(
????grpc.UnaryInterceptor(
????????grpc_middleware.ChainUnaryServer(
????????????authInterceptor,
????????????grpc_validator.UnaryServerInterceptor(),
????????),
????),
????grpc.StreamInterceptor(
????????grpc_middleware.ChainStreamServer(
????????????grpc_validator.StreamServerInterceptor(),
????????),
????),
)

除了上文的驗證器,又多了 Token 認(rèn)證攔截器 authInterceptor。

最后是客戶端改造,客戶端需要實現(xiàn) PerRPCCredentials 接口。

type?PerRPCCredentials?interface?{
????//?GetRequestMetadata?gets?the?current?request?metadata,?refreshing
????//?tokens?if?required.?This?should?be?called?by?the?transport?layer?on
????//?each?request,?and?the?data?should?be?populated?in?headers?or?other
????//?context.?If?a?status?code?is?returned,?it?will?be?used?as?the?status
????//?for?the?RPC.?uri?is?the?URI?of?the?entry?point?for?the?request.
????//?When?supported?by?the?underlying?implementation,?ctx?can?be?used?for
????//?timeout?and?cancellation.
????//?TODO(zhaoq):?Define?the?set?of?the?qualified?keys?instead?of?leaving
????//?it?as?an?arbitrary?string.
????GetRequestMetadata(ctx?context.Context,?uri?...string)?(
????????map[string]string,????error,
????)
????//?RequireTransportSecurity?indicates?whether?the?credentials?requires
????//?transport?security.
????RequireTransportSecurity()?bool
}

GetRequestMetadata 方法返回認(rèn)證需要的必要信息,RequireTransportSecurity 方法表示是否啟用安全鏈接,在生產(chǎn)環(huán)境中,一般都是啟用的,但為了測試方便,暫時這里不啟用了。

實現(xiàn)接口:

type?Authentication?struct?{
????User?????string
????Password?string
}
func?(a?*Authentication)?GetRequestMetadata(context.Context,?...string)?(
????map[string]string,?error,
)?{
????return?map[string]string{"user":?a.User,?"password":?a.Password},?nil
}
func?(a?*Authentication)?RequireTransportSecurity()?bool?{
????return?false
}

連接:

conn,?err?:=?grpc.Dial("localhost:50051",?grpc.WithInsecure(),?grpc.WithPerRPCCredentials(&auth))

好了,現(xiàn)在我們的服務(wù)就有 Token 認(rèn)證功能了。如果用戶名或密碼錯誤,客戶端就會收到:

2021/10/11?20:39:35?rpc?error:?code?=?Unauthenticated?desc?=?invalid?token
exit?status?1

如果用戶名和密碼正確,則可以正常返回。

單向證書認(rèn)證

證書認(rèn)證分兩種方式:

  • 單向認(rèn)證
  • 雙向認(rèn)證

先看一下單向認(rèn)證方式:

生成證書

首先通過 openssl 工具生成自簽名的 SSL 證書。

1、生成私鑰:

openssl?genrsa?-des3?-out?server.pass.key?2048

2、去除私鑰中密碼:

openssl?rsa?-in?server.pass.key?-out?server.key

3、生成 csr 文件:

openssl?req?-new?-key?server.key?-out?server.csr?-subj?"/C=CN/ST=beijing/L=beijing/O=grpcdev/OU=grpcdev/CN=example.grpcdev.cn"

4、生成證書:

openssl?x509?-req?-days?365?-in?server.csr?-signkey?server.key?-out?server.crt

再多說一句,分別介紹一下 X.509 證書包含的三個文件:key,csr 和 crt。

  • key: 服務(wù)器上的私鑰文件,用于對發(fā)送給客戶端數(shù)據(jù)的加密,以及對從客戶端接收到數(shù)據(jù)的解密。
  • csr: 證書簽名請求文件,用于提交給證書頒發(fā)機構(gòu)(CA)對證書簽名。
  • crt: 由證書頒發(fā)機構(gòu)(CA)簽名后的證書,或者是開發(fā)者自簽名的證書,包含證書持有人的信息,持有人的公鑰,以及簽署者的簽名等信息。

gRPC 代碼

證書有了之后,剩下的就是改造程序了,首先是服務(wù)端代碼。

//?證書認(rèn)證-單向認(rèn)證
creds,?err?:=?credentials.NewServerTLSFromFile("keys/server.crt",?"keys/server.key")
if?err?!=?nil?{
????log.Fatal(err)
????return
}
server?:=?grpc.NewServer(grpc.Creds(creds))

只有幾行代碼需要修改,很簡單,接下來是客戶端。

由于是單向認(rèn)證,不需要為客戶端單獨生成證書,只需要把服務(wù)端的 crt 文件拷貝到客戶端對應(yīng)目錄下即可。

//?證書認(rèn)證-單向認(rèn)證
creds,?err?:=?credentials.NewClientTLSFromFile("keys/server.crt",?"example.grpcdev.cn")
if?err?!=?nil?{
????log.Fatal(err)
????return
}
conn,?err?:=?grpc.Dial("localhost:50051",?grpc.WithTransportCredentials(creds))

好了,現(xiàn)在我們的服務(wù)就支持單向證書認(rèn)證了。

但是還沒完,這里可能會遇到一個問題:

2021/10/11?21:32:37?rpc?error:?code?=?Unavailable?desc?=?connection?error:?desc?=?"transport:?authentication?handshake?failed:?x509:?certificate?relies?on?legacy?Common?Name?field,?use?SANs?or?temporarily?enable?Common?Name?matching?with?GODEBUG=x509ignoreCN=0"
exit?status?1

原因是 Go 1.15 開始廢棄了 CommonName,推薦使用 SAN 證書。如果想要兼容之前的方式,可以通過設(shè)置環(huán)境變量的方式支持,如下:

export?GODEBUG="x509ignoreCN=0"

但是需要注意,從 Go 1.17 開始,環(huán)境變量就不再生效了,必須通過 SAN 方式才行。所以,為了后續(xù)的 Go 版本升級,還是早日支持為好。

雙向證書認(rèn)證

最后來看看雙向證書認(rèn)證。

生成帶 SAN 的證書

還是先生成證書,但這次有一點不一樣,我們需要生成帶 SAN 擴展的證書。

什么是 SAN?

SAN(Subject Alternative Name)是 SSL 標(biāo)準(zhǔn) x509 中定義的一個擴展。使用了 SAN 字段的 SSL 證書,可以擴展此證書支持的域名,使得一個證書可以支持多個不同域名的解析。

將默認(rèn)的 OpenSSL 配置文件拷貝到當(dāng)前目錄。

Linux 系統(tǒng)在:

/etc/pki/tls/openssl.cnf

Mac 系統(tǒng)在:

/System/Library/OpenSSL/openssl.cnf

修改臨時配置文件,找到 [ req ] 段落,然后將下面語句的注釋去掉。

req_extensions?=?v3_req?#?The?extensions?to?add?to?a?certificate?request

接著添加以下配置:

[?v3_req?]
#?Extensions?to?add?to?a?certificate?request
basicConstraints?=?CA:FALSE
keyUsage?=?nonRepudiation,?digitalSignature,?keyEncipherment
subjectAltName?=?@alt_names
[?alt_names?]
DNS.1?=?www.example.grpcdev.cn

[ alt_names ] 位置可以配置多個域名,比如:

[?alt_names?]
DNS.1?=?www.example.grpcdev.cn
DNS.2?=?www.test.grpcdev.cn

為了測試方便,這里只配置一個域名。

1、生成 ca 證書:

openssl?genrsa?-out?ca.key?2048
openssl?req?-x509?-new?-nodes?-key?ca.key?-subj?"/CN=example.grpcdev.com"?-days?5000?-out?ca.pem

2、生成服務(wù)端證書:

#?生成證書
openssl?req?-new?-nodes?\
????-subj?"/C=CN/ST=Beijing/L=Beijing/O=grpcdev/OU=grpcdev/CN=www.example.grpcdev.cn"?\
????-config?<(cat?openssl.cnf?\
????????<(printf?"[SAN]\nsubjectAltName=DNS:www.example.grpcdev.cn"))?\
????-keyout?server.key?\
????-out?server.csr
#?簽名證書
openssl?x509?-req?-days?365000?\
????-in?server.csr?-CA?ca.pem?-CAkey?ca.key?-CAcreateserial?\
????-extfile?<(printf?"subjectAltName=DNS:www.example.grpcdev.cn")?\
????-out?server.pem

3、生成客戶端證書:

#?生成證書
openssl?req?-new?-nodes?\
????-subj?"/C=CN/ST=Beijing/L=Beijing/O=grpcdev/OU=grpcdev/CN=www.example.grpcdev.cn"?\
????-config?<(cat?openssl.cnf?\
????????<(printf?"[SAN]\nsubjectAltName=DNS:www.example.grpcdev.cn"))?\
????-keyout?client.key?\
????-out?client.csr
#?簽名證書
openssl?x509?-req?-days?365000?\
????-in?client.csr?-CA?ca.pem?-CAkey?ca.key?-CAcreateserial?\
????-extfile?<(printf?"subjectAltName=DNS:www.example.grpcdev.cn")?\
????-out?client.pem

gRPC 代碼

接下來開始修改代碼,先看服務(wù)端:

//?證書認(rèn)證-雙向認(rèn)證
//?從證書相關(guān)文件中讀取和解析信息,得到證書公鑰、密鑰對
cert,?_?:=?tls.LoadX509KeyPair("cert/server.pem",?"cert/server.key")
//?創(chuàng)建一個新的、空的?CertPool
certPool?:=?x509.NewCertPool()
ca,?_?:=?ioutil.ReadFile("cert/ca.pem")
//?嘗試解析所傳入的 PEM 編碼的證書。如果解析成功會將其加到 CertPool 中,便于后面的使用
certPool.AppendCertsFromPEM(ca)
//?構(gòu)建基于?TLS?的?TransportCredentials?選項
creds?:=?credentials.NewTLS(&tls.Config{
????//?設(shè)置證書鏈,允許包含一個或多個
????Certificates:?[]tls.Certificate{cert},
????//?要求必須校驗客戶端的證書。可以根據(jù)實際情況選用以下參數(shù)
????ClientAuth:?tls.RequireAndVerifyClientCert,
????//?設(shè)置根證書的集合,校驗方式使用?ClientAuth?中設(shè)定的模式
????ClientCAs:?certPool,
})

再看客戶端:

//?證書認(rèn)證-雙向認(rèn)證
//?從證書相關(guān)文件中讀取和解析信息,得到證書公鑰、密鑰對
cert,?_?:=?tls.LoadX509KeyPair("cert/client.pem",?"cert/client.key")
//?創(chuàng)建一個新的、空的?CertPool
certPool?:=?x509.NewCertPool()
ca,?_?:=?ioutil.ReadFile("cert/ca.pem")
//?嘗試解析所傳入的 PEM 編碼的證書。如果解析成功會將其加到 CertPool 中,便于后面的使用
certPool.AppendCertsFromPEM(ca)
//?構(gòu)建基于?TLS?的?TransportCredentials?選項
creds?:=?credentials.NewTLS(&tls.Config{
????//?設(shè)置證書鏈,允許包含一個或多個
????Certificates:?[]tls.Certificate{cert},
????//?要求必須校驗客戶端的證書。可以根據(jù)實際情況選用以下參數(shù)
????ServerName:?"www.example.grpcdev.cn",
????RootCAs:????certPool,
})

大功告成。

Python 客戶端

前面已經(jīng)說了,gRPC 是跨語言的,那么,本文最后我們用 Python 寫一個客戶端,來請求 Go 服務(wù)端。

使用最簡單的方式來實現(xiàn):

proto 文件就使用最開始的「基礎(chǔ)模板」的 proto 文件:

syntax?=?"proto3";
package?proto;
//?The?greeting?service?definition.
service?Greeter?{
????//?Sends?a?greeting
????rpc?SayHello?(HelloRequest)?returns?(HelloReply)?{}
????//?Sends?stream?message
????rpc?SayHelloStream?(stream?HelloRequest)?returns?(stream?HelloReply)?{}
}
//?The?request?message?containing?the?user's?name.
?message?HelloRequest?{
????string?name?=?1;
}
//?The?response?message?containing?the?greetings
message?HelloReply?{
????string?message?=?1;
}

同樣的,也需要通過命令行的方式生成 pb.py 文件:

python3?-m?grpc_tools.protoc?-I?.?--python_out=.?--grpc_python_out=.?./*.proto

執(zhí)行成功之后會在目錄下生成 helloworld_pb2.py 和 helloworld_pb2_grpc.py 兩個文件。

這個過程也可能會報錯:

ModuleNotFoundError:?No?module?named?'grpc_tools'

別慌,是缺少包,安裝就好:

pip3?install?grpcio
pip3?install?grpcio-tools

最后看一下 Python 客戶端代碼:

import?grpc
import?helloworld_pb2
import?helloworld_pb2_grpc
def?main():
????channel?=?grpc.insecure_channel("127.0.0.1:50051")
????stub?=?helloworld_pb2_grpc.GreeterStub(channel)
????response?=?stub.SayHello(helloworld_pb2.HelloRequest(name="zhangsan"))
????print(response.message)
if?__name__?==?'__main__':
????main()

這樣,就可以通過 Python 客戶端請求 Go 啟的服務(wù)端服務(wù)了。

總結(jié)

本文通過實戰(zhàn)角度出發(fā),直接用代碼說話,來說明 gRPC 的一些應(yīng)用。

內(nèi)容包括簡單的 gRPC 服務(wù),流處理模式,驗證器,Token 認(rèn)證和證書認(rèn)證。

除此之外,還有其他值得研究的內(nèi)容,比如超時控制,REST 接口和負(fù)載均衡等。以后還會抽時間繼續(xù)完善剩下這部分內(nèi)容。

本文中的代碼都經(jīng)過測試驗證,可以直接執(zhí)行,并且已經(jīng)上傳到 GitHub,小伙伴們可以一遍看源碼,一遍對照文章內(nèi)容來學(xué)習(xí)。

源碼地址:

https://github.com/yongxinz/go-example/tree/main/grpc-example

https://github.com/yongxinz/gopher/tree/main/blog

以上就是Go語言程序開發(fā)gRPC服務(wù)的詳細(xì)內(nèi)容,更多關(guān)于Go語言開發(fā)gRPC服務(wù)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Golang的Fork/Join實現(xiàn)代碼

    Golang的Fork/Join實現(xiàn)代碼

    Fork/Join本質(zhì)上是一種任務(wù)分解,將一個很大的任務(wù)分解成若干個小任務(wù),然后再對小任務(wù)進(jìn)一步分解,直到最小顆粒度,然后并發(fā)執(zhí)行,對Golang的Fork/Join實現(xiàn)代碼感興趣的朋友跟隨小編一起看看吧
    2023-01-01
  • golang反向代理設(shè)置host不生效的問題解決

    golang反向代理設(shè)置host不生效的問題解決

    在使用golang的httputil做反向代理的時候,發(fā)現(xiàn)一個奇怪的現(xiàn)象,上游網(wǎng)關(guān)必須要設(shè)置host才行,不設(shè)置host的話,golang服務(wù)反向代理請求下游會出現(xiàn)http 503錯誤,接下來通過本文給大家介紹golang反向代理設(shè)置host不生效問題,感興趣的朋友一起看看吧
    2023-05-05
  • Go語言中實現(xiàn)Unix風(fēng)格的進(jìn)程管道方法實例

    Go語言中實現(xiàn)Unix風(fēng)格的進(jìn)程管道方法實例

    這篇文章主要為大家介紹了Go語言中實現(xiàn)Unix風(fēng)格的進(jìn)程管道方法實例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Go語言中的閉包詳解

    Go語言中的閉包詳解

    本文詳細(xì)講解了Go語言中的閉包,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • 解決golang 關(guān)于全局變量的坑

    解決golang 關(guān)于全局變量的坑

    這篇文章主要介紹了解決golang 關(guān)于全局變量的坑,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • go中string、int、float相互轉(zhuǎn)換的實現(xiàn)示例

    go中string、int、float相互轉(zhuǎn)換的實現(xiàn)示例

    本文主要介紹了go中string、int、float相互轉(zhuǎn)換的實現(xiàn)示例,文中根據(jù)實例編碼詳細(xì)介紹的十分詳盡,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Golang中的select語句及其應(yīng)用實例

    Golang中的select語句及其應(yīng)用實例

    本文將介紹Golang中的select語句的使用方法和作用,并通過代碼示例展示其在并發(fā)編程中的實際應(yīng)用,此外,還提供了一些與select相關(guān)的面試題,幫助讀者更好地理解和應(yīng)用select語句
    2023-12-12
  • Go語言空結(jié)構(gòu)體詳解

    Go語言空結(jié)構(gòu)體詳解

    本文主要介紹了Go語言空結(jié)構(gòu)體詳解,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 在?Go?語言中使用?regexp?包處理正則表達(dá)式的操作

    在?Go?語言中使用?regexp?包處理正則表達(dá)式的操作

    正則表達(dá)式是處理字符串時一個非常強大的工具,而?Go?語言的?regexp?包提供了簡單而強大的接口來使用正則表達(dá)式,本文將介紹如何在?Go?中使用?regexp?包來編譯和執(zhí)行正則表達(dá)式,以及如何從文本中匹配和提取信息,感興趣的朋友一起看看吧
    2023-12-12
  • Go語言中的錯誤處理最佳實踐詳解

    Go語言中的錯誤處理最佳實踐詳解

    這篇文章主要為大家詳細(xì)介紹了Go語言中的錯誤處理的相關(guān)知識,文中的示例代碼講解詳細(xì),對我們深入了解Go語言有一定的幫助,需要的可以參考下
    2023-08-08

最新評論

大宁县| 龙川县| 曲周县| 邻水| 中西区| 藁城市| 榆社县| 遵义县| 盈江县| 广州市| 高尔夫| 武汉市| 米泉市| 定陶县| 黔江区| 肇庆市| 通海县| 兴山县| 本溪市| 融水| 巴林左旗| 平邑县| 东宁县| 体育| 贵港市| 青川县| 新宁县| 文安县| 钟祥市| 罗定市| 和平县| 合川市| 田东县| 启东市| 肥西县| 滨海县| 云南省| 万安县| 阳城县| 靖西县| 施秉县|