wordpress 分享本文,西安seo关键字优化,课程网站资源建设小结,咸阳城乡建设局网站protobuf
官方文档 基本数据类型
.proto TypeNotesGo Typedoublefloat64floatfloat32int32使用变长编码#xff0c;对于负值的效率很低#xff0c;如果你的域有可能有负值#xff0c;请使用sint64替代int32uint32使用变长编码uint32uint64使用变长编码uint64sint32使用变长…protobuf
官方文档 基本数据类型
.proto TypeNotesGo Typedoublefloat64floatfloat32int32使用变长编码对于负值的效率很低如果你的域有可能有负值请使用sint64替代int32uint32使用变长编码uint32uint64使用变长编码uint64sint32使用变长编码这些编码在负值时比int32高效的多int32sint64使用变长编码有符号的整型值。编码时比通常的int64高效。int64fixed32总是4个字节如果数值总是比总是比228大的话这个类型会比uint32高效。uint32fixed64总是8个字节如果数值总是比总是比256大的话这个类型会比uint64高效。uint64sfixed32总是4个字节int32sfixed64总是8个字节int64boolboolstring一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。stringbytes可能包含任意顺序的字节数据。[]byte
在java中无符号32位和64位整型被表示成他们的整型对应形似最高位被储存在标志位中。对于所有的情况设定值会执行类型检查以确保此值是有效。64位或者无符号32位整型在解码时被表示成为ilong但是在设置时可以使用int型值设定在所有的情况下值必须符合其设置其类型的要求。python中string被表示成在解码时表示成unicode。但是一个ASCIIstring可以被表示成str类型。Integer在64位的机器上使用string在32位机器上使用 当一个消息被解析的时候如果被编码的信息不包含一个特定的singular元素被解析的对象锁对应的域被设置位一个默认值对于不同类型指定如下 ● 对于strings默认是一个空string ● 对于bytes默认是一个空的bytes ● 对于bools默认是false ● 对于数值类型默认是0 ● 对于枚举默认是第一个定义的枚举值必须为0; ● 对于消息类型message域没有被设置确切的消息是根据语言确定的详见generated code guide 对于可重复域的默认值是空通常情况下是对应语言中空列表。 注对于标量消息域一旦消息被解析就无法判断域释放被设置为默认值例如例如boolean值是否被设置为false还是根本没有被设置。你应该在定义你的消息类型时非常注意。例如比如你不应该定义boolean的默认值false作为任何行为的触发方式。也应该注意如果一个标量消息域被设置为标志位这个值不应该被序列化传输。 查看generated code guide选择你的语言的默认值的工作细节。
proto文件中引入另一个proto文件
1.被引用的proto要先转成go代码 2.使用protobuf提供的proto引用格式与自定义的proto引用格式不同 base.proto
syntax proto3;
// 生成proto文件所在包路径
package protos;
// 影响go文件生成位置和包名
//.是当前文件夹
option go_package .;proto;
message Empty{}
message Pong{string id1;
}转成go代码
protoc --go_out. --go_optpathssource_relative --go-grpc_out. --go-grpc_optpathssource_relative base.proto hello.proto
syntax proto3;
// 生成proto文件所在包路径
package protos;
// 影响go文件生成位置和包名
//.是当前文件夹
option go_package .;proto;
import base.proto;
import google/protobuf/empty.proto;
service Greeter{rpc SayHello(HelloRquest)returns(HelloReply);//hello接口rpc Ping(google.protobuf.Empty)returns (Pong);
}
message HelloRquest{string name1;//1是编号不是值string url2;
}
message HelloReply{string message1;
}转成go代码
protoc --go_out. --go_optpathssource_relative --go-grpc_out. --go-grpc_optpathssource_relative hello.protomessage嵌套
目录结构
hello.proto
syntax proto3;
// 生成proto文件所在包路径
package protos;
// 影响go文件生成位置和包名
//.是当前文件夹
option go_package .;proto;
import base.proto;
import google/protobuf/empty.proto;
service Greeter{rpc SayHello(HelloRquest)returns(HelloReply);//hello接口rpc Ping(google.protobuf.Empty)returns (Pong);
}
message HelloRquest{string name1;//1是编号不是值string url2;
}message HelloReply{string message1;repeated Result data2;message Result{string name1;string url2;}
}转换
protoc --go_out. --go_optpathssource_relative --go-grpc_out. --go-grpc_optpathssource_relative hello.proto使用
package mainimport GolangStudy/Introduction/grpc/example4/protofunc main() {_ proto.HelloReply_Result{}
}枚举类型
目录结构 hello2.proto
syntax proto3;// 生成proto文件所在包路径
package protos;
// 影响go文件生成位置和包名
//.是当前文件夹
option go_package .;proto1;
service Greeter{rpc SayHello(HelloRquest)returns(HelloReply);//hello接口
}
enum Gender{MALE0;FEMALE1;
}
message HelloRquest{string name1;//1是编号不是值Gender g3;
}
message HelloReply{string message1;
}转换
protoc --go_out. --go_optpathssource_relative --go-grpc_out. --go-grpc_optpathssource_relative hello2.proto调用
package mainimport (_ GolangStudy/Introduction/grpc/example4/protoGolangStudy/Introduction/grpc/example4/proto1contextfmtgoogle.golang.org/grpc
)func main() {// _ proto.HelloReply_Result{}conn, err : grpc.Dial(127.0.0.1:8080, grpc.WithInsecure())if err ! nil {panic(err)}defer conn.Close()c : proto1.NewGreeterClient(conn)r, err : c.SayHello(context.Background(), proto1.HelloRquest{Name: bobby,G: proto1.Gender_FEMALE,})if err ! nil {panic(err)}fmt.Println(r.Message)
}
map类型
hello2.proto
syntax proto3;// 生成proto文件所在包路径
package protos;
// 影响go文件生成位置和包名
//.是当前文件夹
option go_package .;proto1;
service Greeter{rpc SayHello(HelloRquest)returns(HelloReply);//hello接口
}
enum Gender{MALE0;FEMALE1;
}
message HelloRquest{string name1;//1是编号不是值Gender g2;mapstring,string mp3;
}
message HelloReply{string message1;
}转换
protoc --go_out. --go_optpathssource_relative --go-grpc_out. --go-grpc_optpathssource_relative hello2.proto使用
package mainimport (_ GolangStudy/Introduction/grpc/example4/protoGolangStudy/Introduction/grpc/example4/proto1contextfmtgoogle.golang.org/grpc
)func main() {// _ proto.HelloReply_Result{}conn, err : grpc.Dial(127.0.0.1:8080, grpc.WithInsecure())if err ! nil {panic(err)}defer conn.Close()c : proto1.NewGreeterClient(conn)r, err : c.SayHello(context.Background(), proto1.HelloRquest{Name: bobby,G: proto1.Gender_FEMALE,Mp: map[string]string{name: bobby,company: mooc,},})if err ! nil {panic(err)}fmt.Println(r.Message)
}
timestamp类型
hello2.proto
syntax proto3;// 生成proto文件所在包路径
package protos;
// 影响go文件生成位置和包名
//.是当前文件夹
option go_package .;proto1;
import google/protobuf/timestamp.proto;
service Greeter{rpc SayHello(HelloRquest)returns(HelloReply);//hello接口
}
enum Gender{MALE0;FEMALE1;
}
message HelloRquest{string name1;//1是编号不是值Gender g2;mapstring,string mp3;google.protobuf.Timestamp addTime4;
}
message HelloReply{string message1;
}转换
protoc --go_out. --go_optpathssource_relative --go-grpc_out. --go-grpc_optpathssource_relative hello2.proto使用
package mainimport (_ GolangStudy/Introduction/grpc/example4/protoGolangStudy/Introduction/grpc/example4/proto1contextfmttimegoogle.golang.org/grpcgoogle.golang.org/protobuf/types/known/timestamppb
)func main() {// _ proto.HelloReply_Result{}conn, err : grpc.Dial(127.0.0.1:8080, grpc.WithInsecure())if err ! nil {panic(err)}defer conn.Close()c : proto1.NewGreeterClient(conn)r, err : c.SayHello(context.Background(), proto1.HelloRquest{Name: bobby,G: proto1.Gender_FEMALE,Mp: map[string]string{name: bobby,company: mooc,},AddTime: timestamppb.New(time.Now()),})if err ! nil {panic(err)}fmt.Println(r.Message)
}
grpc
metadata
grpc让我们可以像本地调用一样实现远程调用对于每一次的RPC调用中都可能会有一些有用的数据而这些数据就可以通过metadata来传递。metadata是以key-value的形式存储数据的其中key是string类型而value是[]string即一个字符串数组类型。metadata使得client和server能够为对方提供关于本次调用的一些信息就像一次http请求的RequestHeader和ResponseHeader一样。http中header的生命周周期是一次http请求那么metadata的生命周期就是一次rpc调用。 实例化
//第一种方式
md : metadata.New(map[string]string{key1: val1, key2: val2})
//第二种方式 key不区分大小写会被统一转成小写。
md : metadata.Pairs(key1, val1,key1, val1-2, // key1 will have map value []string{val1, val1-2}key2, val2,
)使用
//发送md : metadata.Pairs(key, val)// 新建一个有 metadata 的 context
ctx : metadata.NewOutgoingContext(context.Background(), md)// 单向 RPC
response, err : client.SomeRPC(ctx, someRequest)
//接收
func (s *server) SomeRPC(ctx context.Context, in *pb.SomeRequest) (*pb.SomeResponse, err) {md, ok : metadata.FromIncomingContext(ctx)// do something with metadata
}使用例子
拦截器
grpc Go支持“拦截器”即在将请求传递到用户的应用程序逻辑之前在 grpc服务器上执行的中间件或者在用户调用时在 grpc 客户端上执行的中间件。它是实现常见模式的完美方式身份验证、日志记录、跟踪、指标、验证、重试、速率限制等它们可以成为出色的通用构建块让您轻松构建多个微服务。 实例 目录结构 hello.proto
syntax proto3;
option go_package .;proto;
service Greeter {rpc SayHello (HelloRequest) returns (HelloReply);
}
//将 sessionid放入 放入cookie中 http协议
message HelloRequest {string name 1;
}message HelloReply {string message 1;
}生成
protoc --go_out. --go_optpathssource_relative --go-grpc_out. --go-grpc_optpathssource_relative hello2.protoserver
package mainimport (contextfmtnetgoogle.golang.org/grpcGolangStudy/Introduction/grpc/interpretor/proto
)type Server struct{}func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply,error) {return proto.HelloReply{Message: hello request.Name,}, nil
}func main() {var interceptor grpc.UnaryServerInterceptorinterceptor func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {// 继续处理请求fmt.Println(接收到新请求)res, err : handler(ctx, req)fmt.Println(请求处理完成)return res, err}var opts []grpc.ServerOptionopts append(opts, grpc.UnaryInterceptor(interceptor))g : grpc.NewServer(opts...)proto.RegisterGreeterServer(g, Server{})lis, err : net.Listen(tcp, 0.0.0.0:50051)if err ! nil {panic(failed to listen: err.Error())}err g.Serve(lis)if err ! nil {panic(failed to start grpc: err.Error())}
}
client
package mainimport (contextfmttimegoogle.golang.org/grpcGolangStudy/Introduction/grpc/interpretor/proto
)func interceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {start : time.Now()err : invoker(ctx, method, req, reply, cc, opts...)fmt.Printf(method%s req%v rep%v duration%s error%v\n, method, req, reply, time.Since(start), err)return err
}func main() {//streamvar opts []grpc.DialOptionopts append(opts, grpc.WithInsecure())// 指定客户端interceptoropts append(opts, grpc.WithUnaryInterceptor(interceptor))conn, err : grpc.Dial(localhost:50051, opts...)if err ! nil {panic(err)}defer conn.Close()c : proto.NewGreeterClient(conn)r, err : c.SayHello(context.Background(), proto.HelloRequest{Name: bobby})if err ! nil {panic(err)}fmt.Println(r.Message)
}
拦截器框架
auth认证
hello.proto
syntax proto3;
option go_package .;proto;
service Greeter {rpc SayHello (HelloRequest) returns (HelloReply);
}message HelloRequest {string name 1;
}message HelloReply {string message 1;
}生成
protoc --go_out. --go_optpathssource_relative --go-grpc_out. --go-grpc_optpathssource_relative hello2.protoserver
package mainimport (contextfmtnetgoogle.golang.org/grpcgoogle.golang.org/grpc/codesgoogle.golang.org/grpc/metadatagoogle.golang.org/grpc/statusGolangStudy/Introduction/grpc/token_auth/proto
)type Server struct{}func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply,error) {return proto.HelloReply{Message: hello request.Name,}, nil
}func main() {var interceptor grpc.UnaryServerInterceptorinterceptor func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {// 继续处理请求fmt.Println(接收到新请求)md, ok : metadata.FromIncomingContext(ctx)if !ok {return resp, status.Error(codes.Unauthenticated, 无token认证信息)}var (appid stringappkey string)if va1, ok : md[appid]; ok {appid va1[0]}if va1, ok : md[appkey]; ok {appkey va1[0]}fmt.Println(appid, appkey)if appid ! 101010 || appkey ! i am key {return resp, status.Error(codes.Unauthenticated, 无token认证信息)}res, err : handler(ctx, req)fmt.Println(请求处理完成)return res, err}var opts []grpc.ServerOptionopts append(opts, grpc.UnaryInterceptor(interceptor))g : grpc.NewServer(opts...)proto.RegisterGreeterServer(g, Server{})lis, err : net.Listen(tcp, 0.0.0.0:50051)if err ! nil {panic(failed to listen: err.Error())}err g.Serve(lis)if err ! nil {panic(failed to start grpc: err.Error())}
}
client
package mainimport (contextfmtGolangStudy/Introduction/grpc/token_auth/protogoogle.golang.org/grpc
)type customCredential struct{}func (cc *customCredential) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {return map[string]string{appid: 101010,appkey: i am key,}, nil
}// RequireTransportSecurity indicates whether the credentials requires
// transport security.
func (cc *customCredential) RequireTransportSecurity() bool {return false
}
func main() {// interceptor : func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {// start : time.Now()// md : metadata.New(map[string]string{// appid: 101010,// appkey: i am key,// })// ctx metadata.NewOutgoingContext(context.Background(), md)// err : invoker(ctx, method, req, reply, cc, opts...)// fmt.Printf(method%s req%v rep%v duration%s error%v\n, method, req, reply, time.Since(start), err)// return err// }//streamvar opts []grpc.DialOptionopts append(opts, grpc.WithInsecure())// 指定客户端interceptoropts append(opts, grpc.WithPerRPCCredentials(customCredential{}))conn, err : grpc.Dial(127.0.0.1:50051, opts...)if err ! nil {panic(err)}defer conn.Close()c : proto.NewGreeterClient(conn)r, err : c.SayHello(context.Background(), proto.HelloRequest{Name: bobby})if err ! nil {panic(err)}fmt.Println(r.Message)
}
验证器
实例 Protocol Buffer Validation 使用的mac电脑使用官网的第二种第三种都试过了不可以第二种在$GOPATH:bin找不到protoc-gen-validate文件第三种能找到但是将proto转换成go文件时会一直报如下错误最后使用了第一种才成功。
protoc-gen-validate: program not found or is not executable
Please specify a program using absolute path or make sure the program is available in your PATH system variable
--validate_out: protoc-gen-validate: Plugin failed with status code 1.//第一种
go install github.com/envoyproxy/protoc-gen-validatelatest//第二种
go get -d github.com/envoyproxy/protoc-gen-validate//第三种
git clone https://github.com/bufbuild/protoc-gen-validate.git
cd $GOPATH/bin
cd protoc-gen-validate
make buildhello.proto
syntax proto3;option go_package.;proto;
import validate.proto;service Greeter {rpc SayHello (Person) returns (Person);
}message Person {uint64 id 1 [(validate.rules).uint64.gt 999];string email 2 [(validate.rules).string.email true];string mobile 3 [(validate.rules).string {pattern: ^1[3456789]\\d{9}$}];}转换
protoc --go_out. --go_optpathssource_relative --go-grpc_out. --go-grpc_optpathssource_relative --validate_outlanggo:. hello.protoclient
package mainimport (GolangStudy/Introduction/grpc/validate/protocontextfmtgoogle.golang.org/grpc
)type customCredential struct{}func main() {var opts []grpc.DialOption//opts append(opts, grpc.WithUnaryInterceptor(interceptor))opts append(opts, grpc.WithInsecure())conn, err : grpc.Dial(localhost:50051, opts...)if err ! nil {panic(err)}defer conn.Close()c : proto.NewGreeterClient(conn)//rsp, _ : c.Search(context.Background(), empty.Empty{})rsp, err : c.SayHello(context.Background(), proto.Person{Id: 9999,Email: bobbyqq.com,Mobile: 19999999999,})if err ! nil {panic(err)}fmt.Println(rsp.Id)
}
server
package mainimport (contextnetgoogle.golang.org/grpc/codesgoogle.golang.org/grpc/statusgoogle.golang.org/grpcGolangStudy/Introduction/grpc/validate/proto
)type Server struct{}func (s *Server) SayHello(ctx context.Context, request *proto.Person) (*proto.Person,error) {return proto.Person{Id: 32,}, nil
}type Validator interface {Validate() error
}func main() {var interceptor grpc.UnaryServerInterceptorinterceptor func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {// 继续处理请求if r, ok : req.(Validator); ok {if err : r.Validate(); err ! nil {return nil, status.Error(codes.InvalidArgument, err.Error())}}return handler(ctx, req)}var opts []grpc.ServerOptionopts append(opts, grpc.UnaryInterceptor(interceptor))g : grpc.NewServer(opts...)proto.RegisterGreeterServer(g, Server{})lis, err : net.Listen(tcp, 0.0.0.0:50051)if err ! nil {panic(failed to listen: err.Error())}err g.Serve(lis)if err ! nil {panic(failed to start grpc: err.Error())}
}
错误码
CodeNumberDescriptionOK0Not an error; returned on success.CANCELLED1操作被取消通常是由调用者取消的。UNKNOWN2未知错误。例如当从另一个地址空间接收到的状态值属于该地址空间中未知的错误空间时可能会返回此错误。此外由未返回足够错误信息的 API 引发的错误也可能会转换为此错误。INVALID_ARGUMENT3客户端指定了无效参数。请注意这与 FAILED_PRECONDITION 不同。DEADLINE_EXCEEDED4操作完成之前截止日期已过。对于更改系统状态的操作即使操作已成功完成也可能会返回此错误。例如服务器的成功响应可能会延迟很长时间NOT_FOUND5未找到某些请求的实体例如文件或目录。服务器开发人员请注意如果整个用户类别的请求被拒绝例如逐步推出功能或未记录的许可名单则可以使用 NOT_FOUND。如果拒绝一类用户中的某些用户的请求例如基于用户的访问控制则必须使用 PERMISSION_DENIED。ALREADY_EXISTS6客户端尝试创建的实体例如文件或目录已存在PERMISSION_DENIED7调用者没有执行指定操作的权限。 PERMISSION_DENIED 不得用于因耗尽某些资源而导致的拒绝对于这些错误请使用 RESOURCE_EXHAUSTED 代替。如果无法识别调用者则不得使用 PERMISSION_DENIED对于这些错误请使用 UNAUTHENTICATED。此错误代码并不意味着请求有效或请求的实体存在或满足其他先决条件RESOURCE_EXHAUSTED8某些资源已耗尽可能是每个用户的配额或者可能是整个文件系统空间不足。FAILED_PRECONDITION9操作被拒绝因为系统未处于操作执行所需的状态。例如要删除的目录非空、rmdir 操作应用于非目录等。服务实现者可以使用以下准则来决定 FAILED_PRECONDITION、ABORTED 和 UNAVAILABLE (a) 如果客户端可以仅重试失败的调用。 (b) 如果客户端应在更高级别重试例如当客户端指定的测试和设置失败时指示客户端应重新启动读取-修改-写入序列则使用 ABORTED。 © 如果客户端在系统状态明确修复之前不应重试则使用 FAILED_PRECONDITION。例如如果“rmdir”由于目录非空而失败则应返回 FAILED_PRECONDITION因为除非从目录中删除文件否则客户端不应重试。ABORTED10操作被中止通常是由于并发问题例如定序器检查失败或事务中止。请参阅上面的指南来决定 FAILED_PRECONDITION、ABORTED 和 UNAVAILABLE。OUT_OF_RANGE11尝试的操作超出了有效范围。例如查找或读取文件末尾之后的内容。与 INVALID_ARGUMENT 不同此错误指示如果系统状态发生更改则可以修复的问题。例如如果要求读取不在 [0,2^32-1] 范围内的偏移量32 位文件系统将生成 INVALID_ARGUMENT但如果要求读取超过当前偏移量的偏移量则会生成 OUT_OF_RANGE文件大小。 FAILED_PRECONDITION 和 OUT_OF_RANGE 之间有相当多的重叠。我们建议在应用时使用 OUT_OF_RANGE更具体的错误以便迭代空间的调用者可以轻松查找 OUT_OF_RANGE 错误以检测何时完成。UNIMPLEMENTED12此服务未实现或不支持/启用该操作。INTERNAL13内部错误。这意味着底层系统所期望的一些不变量已经被打破。该错误代码是为严重错误保留的。UNAVAILABLE14该服务目前不可用。这很可能是一种瞬态情况可以通过后退重试来纠正。请注意重试非幂等操作并不总是安全的。DATA_LOSS15不可恢复的数据丢失或损坏。UNAUTHENTICATED16该请求没有该操作的有效身份验证凭据
实例 服务端
status.New(codes.InvalidArgument, invalid username)客户端
st, ok : status.FromError(err)
if !ok {// Error was not a status error
}
st.Message()
st.Code()grpc的超时机制
ctx, cancel : context.WithTimeout(context.TODO(), time.Second*3)
defer cancel()r, err : c.SayHello(ctx, pb.HelloRequest{Name: name})实例