proto 与grpc 详解

protobuf 官方的中文介绍:https://protobuf.com.cn/

标量值类型

一个标量消息字段可以有以下类型之一——该表显示了在 .proto 文件中指定的类型,以及在自动生成的类中对应的类型

Proto 类型	说明
double	
float	
int32	使用可变长度编码。对于编码负数效率低下——如果你的字段可能包含负值,请改用 sint32。
int64	使用可变长度编码。对于编码负数效率低下——如果你的字段可能包含负值,请改用 sint64。
uint32	使用可变长度编码。
uint64	使用可变长度编码。
sint32	使用可变长度编码。有符号整数值。这些比常规的 int32 更高效地编码负数。
sint64	使用可变长度编码。有符号整数值。这些比常规的 int64 更高效地编码负数。
fixed32	总是四个字节。如果值经常大于 228,比 uint32 更高效。
fixed64	总是八个字节。如果值经常大于 256,比 uint64 更高效。
sfixed32	总是四个字节。
sfixed64	总是八个字节。
bool	
string	字符串必须始终包含 UTF-8 编码或 7 位 ASCII 文本,且长度不能超过 232。
bytes	可包含任意字节序列,长度不超过 232。


Proto 类型	C++ 类型	 Java/Kotlin 类型[1]	Python 类型[3]	Go 类型	Ruby 类型	C# 类型	PHP 类型	Dart 类型	Rust 类型
double	double	double	float	float64	Float	double	float	double	f64
float	float	float	float	float32	Float	float	float	double	f32
int32	int32_t	int	int	int32	Fixnum 或 Bignum (根据需要)	int	integer	int	i32
int64	int64_t	long	int/long[4]	int64	Bignum	long	integer/string[6]	Int64	i64
uint32	uint32_t	int[2]	int/long[4]	uint32	Fixnum 或 Bignum (根据需要)	uint	integer	int	u32
uint64	uint64_t	long[2]	int/long[4]	uint64	Bignum	ulong	integer/string[6]	Int64	u64
sint32	int32_t	int	int	int32	Fixnum 或 Bignum (根据需要)	int	integer	int	i32
sint64	int64_t	long	int/long[4]	int64	Bignum	long	integer/string[6]	Int64	i64
fixed32	uint32_t	int[2]	int/long[4]	uint32	Fixnum 或 Bignum (根据需要)	uint	integer	int	u32
fixed64	uint64_t	long[2]	int/long[4]	uint64	Bignum	ulong	integer/string[6]	Int64	u64
sfixed32	int32_t	int	int	int32	Fixnum 或 Bignum (根据需要)	int	integer	int	i32
sfixed64	int64_t	long	int/long[4]	int64	Bignum	long	integer/string[6]	Int64	i64
bool	bool	boolean	bool	bool	TrueClass/FalseClass	bool	boolean	bool	bool
string	string	String	str/unicode[5]	string	String (UTF-8)	string	string	String	ProtoString
bytes	string	ByteString	str (Python 2), bytes (Python 3)	[]byte	String (ASCII-8BIT)	ByteString	string	List	ProtoBytes

字段默认值

当解析消息时,如果编码的消息字节中不包含某个特定字段,那么在解析的对象中访问该字段将返回该字段的默认值。默认值是类型特定的:

  • 对于字符串,默认值是空字符串。
  • 对于字节,默认值是空字节。
  • 对于布尔值,默认值是 false。
  • 对于数值类型,默认值是零。
  • 对于消息字段,该字段未设置。其确切值取决于语言。详情请参阅生成的代码指南
  • 对于枚举,默认值是第一个定义的枚举值,该值必须为 0。请参阅枚举默认值

指定包名与路径

syntax = "proto3";
option go_package = "common/stream/proto/v1";//指定生成的文件存放的目录;以及包名
service Greeter {
    rpc GetStream (StreamReqDate) returns (stream StreamResData);//服务端流模式
    rpc PostStream (stream  StreamReqDate) returns (StreamResData);//客户端流模式
    rpc AllStream (stream  StreamReqDate) returns (stream StreamResData);//双向流模式
}
message StreamReqDate {
    string data =1;
}
message StreamResData {
    string data =1;
}


PS D:\golang\goproject\src\lnhgo\day05\stream_grpc_test\proto> protoc --go_out=. --go-grpc_out=. stream.proto

  生成的目录

image

查看生成的文件stream_grpc.pb

// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.2
// - protoc             v7.35.1
// source: stream.proto

package v1

import (
    context "context"
    grpc "google.golang.org/grpc"
    codes "google.golang.org/grpc/codes"
    status "google.golang.org/grpc/status"
)

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9

const (
    Greeter_GetStream_FullMethodName  = "/Greeter/GetStream"
    Greeter_PostStream_FullMethodName = "/Greeter/PostStream"
    Greeter_AllStream_FullMethodName  = "/Greeter/AllStream"
)

// GreeterClient is the client API for Greeter service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type GreeterClient interface {
    GetStream(ctx context.Context, in *StreamReqDate, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamResData], error)
    PostStream(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[StreamReqDate, StreamResData], error)
    AllStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[StreamReqDate, StreamResData], error)
}

type greeterClient struct {
    cc grpc.ClientConnInterface
}

func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient {
    return &greeterClient{cc}
}

func (c *greeterClient) GetStream(ctx context.Context, in *StreamReqDate, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamResData], error) {
    cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
    stream, err := c.cc.NewStream(ctx, &Greeter_ServiceDesc.Streams[0], Greeter_GetStream_FullMethodName, cOpts...)
    if err != nil {
        return nil, err
    }
    x := &grpc.GenericClientStream[StreamReqDate, StreamResData]{ClientStream: stream}
    if err := x.ClientStream.SendMsg(in); err != nil {
        return nil, err
    }
    if err := x.ClientStream.CloseSend(); err != nil {
        return nil, err
    }
    return x, nil
}

// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Greeter_GetStreamClient = grpc.ServerStreamingClient[StreamResData]

func (c *greeterClient) PostStream(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[StreamReqDate, StreamResData], error) {
    cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
    stream, err := c.cc.NewStream(ctx, &Greeter_ServiceDesc.Streams[1], Greeter_PostStream_FullMethodName, cOpts...)
    if err != nil {
        return nil, err
    }
    x := &grpc.GenericClientStream[StreamReqDate, StreamResData]{ClientStream: stream}
    return x, nil
}

// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Greeter_PostStreamClient = grpc.ClientStreamingClient[StreamReqDate, StreamResData]

func (c *greeterClient) AllStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[StreamReqDate, StreamResData], error) {
    cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
    stream, err := c.cc.NewStream(ctx, &Greeter_ServiceDesc.Streams[2], Greeter_AllStream_FullMethodName, cOpts...)
    if err != nil {
        return nil, err
    }
    x := &grpc.GenericClientStream[StreamReqDate, StreamResData]{ClientStream: stream}
    return x, nil
}

// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Greeter_AllStreamClient = grpc.BidiStreamingClient[StreamReqDate, StreamResData]

// GreeterServer is the server API for Greeter service.
// All implementations must embed UnimplementedGreeterServer
// for forward compatibility.
type GreeterServer interface {
    GetStream(*StreamReqDate, grpc.ServerStreamingServer[StreamResData]) error
    PostStream(grpc.ClientStreamingServer[StreamReqDate, StreamResData]) error
    AllStream(grpc.BidiStreamingServer[StreamReqDate, StreamResData]) error
    mustEmbedUnimplementedGreeterServer()
}

// UnimplementedGreeterServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedGreeterServer struct{}

func (UnimplementedGreeterServer) GetStream(*StreamReqDate, grpc.ServerStreamingServer[StreamResData]) error {
    return status.Error(codes.Unimplemented, "method GetStream not implemented")
}
func (UnimplementedGreeterServer) PostStream(grpc.ClientStreamingServer[StreamReqDate, StreamResData]) error {
    return status.Error(codes.Unimplemented, "method PostStream not implemented")
}
func (UnimplementedGreeterServer) AllStream(grpc.BidiStreamingServer[StreamReqDate, StreamResData]) error {
    return status.Error(codes.Unimplemented, "method AllStream not implemented")
}
func (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {}
func (UnimplementedGreeterServer) testEmbeddedByValue()                 {}

// UnsafeGreeterServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to GreeterServer will
// result in compilation errors.
type UnsafeGreeterServer interface {
    mustEmbedUnimplementedGreeterServer()
}

func RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) {
    // If the following call panics, it indicates UnimplementedGreeterServer was
    // embedded by pointer and is nil.  This will cause panics if an
    // unimplemented method is ever invoked, so we test this at initialization
    // time to prevent it from happening at runtime later due to I/O.
    if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
        t.testEmbeddedByValue()
    }
    s.RegisterService(&Greeter_ServiceDesc, srv)
}

func _Greeter_GetStream_Handler(srv interface{}, stream grpc.ServerStream) error {
    m := new(StreamReqDate)
    if err := stream.RecvMsg(m); err != nil {
        return err
    }
    return srv.(GreeterServer).GetStream(m, &grpc.GenericServerStream[StreamReqDate, StreamResData]{ServerStream: stream})
}

// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Greeter_GetStreamServer = grpc.ServerStreamingServer[StreamResData]

func _Greeter_PostStream_Handler(srv interface{}, stream grpc.ServerStream) error {
    return srv.(GreeterServer).PostStream(&grpc.GenericServerStream[StreamReqDate, StreamResData]{ServerStream: stream})
}

// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Greeter_PostStreamServer = grpc.ClientStreamingServer[StreamReqDate, StreamResData]

func _Greeter_AllStream_Handler(srv interface{}, stream grpc.ServerStream) error {
    return srv.(GreeterServer).AllStream(&grpc.GenericServerStream[StreamReqDate, StreamResData]{ServerStream: stream})
}

// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Greeter_AllStreamServer = grpc.BidiStreamingServer[StreamReqDate, StreamResData]

// Greeter_ServiceDesc is the grpc.ServiceDesc for Greeter service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Greeter_ServiceDesc = grpc.ServiceDesc{
    ServiceName: "Greeter",
    HandlerType: (*GreeterServer)(nil),
    Methods:     []grpc.MethodDesc{},
    Streams: []grpc.StreamDesc{
        {
            StreamName:    "GetStream",
            Handler:       _Greeter_GetStream_Handler,
            ServerStreams: true,
        },
        {
            StreamName:    "PostStream",
            Handler:       _Greeter_PostStream_Handler,
            ClientStreams: true,
        },
        {
            StreamName:    "AllStream",
            Handler:       _Greeter_AllStream_Handler,
            ServerStreams: true,
            ClientStreams: true,
        },
    },
    Metadata: "stream.proto",
}
View Code

 

查看生成的文件stream.pb

// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
//     protoc-gen-go v1.36.11
//     protoc        v7.35.1
// source: stream.proto

package v1

import (
    protoreflect "google.golang.org/protobuf/reflect/protoreflect"
    protoimpl "google.golang.org/protobuf/runtime/protoimpl"
    reflect "reflect"
    sync "sync"
    unsafe "unsafe"
)

const (
    // Verify that this generated code is sufficiently up-to-date.
    _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
    // Verify that runtime/protoimpl is sufficiently up-to-date.
    _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)

type StreamReqDate struct {
    state         protoimpl.MessageState `protogen:"open.v1"`
    Data          string                 `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
    unknownFields protoimpl.UnknownFields
    sizeCache     protoimpl.SizeCache
}

func (x *StreamReqDate) Reset() {
    *x = StreamReqDate{}
    mi := &file_stream_proto_msgTypes[0]
    ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
    ms.StoreMessageInfo(mi)
}

func (x *StreamReqDate) String() string {
    return protoimpl.X.MessageStringOf(x)
}

func (*StreamReqDate) ProtoMessage() {}

func (x *StreamReqDate) ProtoReflect() protoreflect.Message {
    mi := &file_stream_proto_msgTypes[0]
    if x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}

// Deprecated: Use StreamReqDate.ProtoReflect.Descriptor instead.
func (*StreamReqDate) Descriptor() ([]byte, []int) {
    return file_stream_proto_rawDescGZIP(), []int{0}
}

func (x *StreamReqDate) GetData() string {
    if x != nil {
        return x.Data
    }
    return ""
}

type StreamResData struct {
    state         protoimpl.MessageState `protogen:"open.v1"`
    Data          string                 `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
    unknownFields protoimpl.UnknownFields
    sizeCache     protoimpl.SizeCache
}

func (x *StreamResData) Reset() {
    *x = StreamResData{}
    mi := &file_stream_proto_msgTypes[1]
    ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
    ms.StoreMessageInfo(mi)
}

func (x *StreamResData) String() string {
    return protoimpl.X.MessageStringOf(x)
}

func (*StreamResData) ProtoMessage() {}

func (x *StreamResData) ProtoReflect() protoreflect.Message {
    mi := &file_stream_proto_msgTypes[1]
    if x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}

// Deprecated: Use StreamResData.ProtoReflect.Descriptor instead.
func (*StreamResData) Descriptor() ([]byte, []int) {
    return file_stream_proto_rawDescGZIP(), []int{1}
}

func (x *StreamResData) GetData() string {
    if x != nil {
        return x.Data
    }
    return ""
}

var File_stream_proto protoreflect.FileDescriptor

const file_stream_proto_rawDesc = "" +
    "\n" +
    "\fstream.proto\"#\n" +
    "\rStreamReqDate\x12\x12\n" +
    "\x04data\x18\x01 \x01(\tR\x04data\"#\n" +
    "\rStreamResData\x12\x12\n" +
    "\x04data\x18\x01 \x01(\tR\x04data2\x99\x01\n" +
    "\aGreeter\x12-\n" +
    "\tGetStream\x12\x0e.StreamReqDate\x1a\x0e.StreamResData0\x01\x12.\n" +
    "\n" +
    "PostStream\x12\x0e.StreamReqDate\x1a\x0e.StreamResData(\x01\x12/\n" +
    "\tAllStream\x12\x0e.StreamReqDate\x1a\x0e.StreamResData(\x010\x01B\x18Z\x16common/stream/proto/v1b\x06proto3"

var (
    file_stream_proto_rawDescOnce sync.Once
    file_stream_proto_rawDescData []byte
)

func file_stream_proto_rawDescGZIP() []byte {
    file_stream_proto_rawDescOnce.Do(func() {
        file_stream_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_stream_proto_rawDesc), len(file_stream_proto_rawDesc)))
    })
    return file_stream_proto_rawDescData
}

var file_stream_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_stream_proto_goTypes = []any{
    (*StreamReqDate)(nil), // 0: StreamReqDate
    (*StreamResData)(nil), // 1: StreamResData
}
var file_stream_proto_depIdxs = []int32{
    0, // 0: Greeter.GetStream:input_type -> StreamReqDate
    0, // 1: Greeter.PostStream:input_type -> StreamReqDate
    0, // 2: Greeter.AllStream:input_type -> StreamReqDate
    1, // 3: Greeter.GetStream:output_type -> StreamResData
    1, // 4: Greeter.PostStream:output_type -> StreamResData
    1, // 5: Greeter.AllStream:output_type -> StreamResData
    3, // [3:6] is the sub-list for method output_type
    0, // [0:3] is the sub-list for method input_type
    0, // [0:0] is the sub-list for extension type_name
    0, // [0:0] is the sub-list for extension extendee
    0, // [0:0] is the sub-list for field type_name
}

func init() { file_stream_proto_init() }
func file_stream_proto_init() {
    if File_stream_proto != nil {
        return
    }
    type x struct{}
    out := protoimpl.TypeBuilder{
        File: protoimpl.DescBuilder{
            GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
            RawDescriptor: unsafe.Slice(unsafe.StringData(file_stream_proto_rawDesc), len(file_stream_proto_rawDesc)),
            NumEnums:      0,
            NumMessages:   2,
            NumExtensions: 0,
            NumServices:   1,
        },
        GoTypes:           file_stream_proto_goTypes,
        DependencyIndexes: file_stream_proto_depIdxs,
        MessageInfos:      file_stream_proto_msgTypes,
    }.Build()
    File_stream_proto = out.File
    file_stream_proto_goTypes = nil
    file_stream_proto_depIdxs = nil
}
View Code

 

生成到上层目录

syntax = "proto3";
option go_package = "../../../common/stream/proto/v1";//指定生成的文件存放的目录;以及包名
service Greeter {
    rpc GetStream (StreamReqDate) returns (stream StreamResData);//服务端流模式
    rpc PostStream (stream  StreamReqDate) returns (StreamResData);//客户端流模式
    rpc AllStream (stream  StreamReqDate) returns (stream StreamResData);//双向流模式
}
message StreamReqDate {
    string data =1;
}
message StreamResData {
    string data =1;
}
生成到上级目录需要添加 --unsafe_allow_out_dir_escape参数
PS D:\golang\goproject\src\lnhgo\day05\stream_grpc_test\proto> protoc --go_out=. --go-grpc_out=. stream.proto --unsafe_allow_out_dir_escape

  查看生成的目录

image

 查看生成的stream_grpc.pb

// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.2
// - protoc             v7.35.1
// source: stream.proto

package v1

import (
    context "context"
    grpc "google.golang.org/grpc"
    codes "google.golang.org/grpc/codes"
    status "google.golang.org/grpc/status"
)

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9

const (
    Greeter_GetStream_FullMethodName  = "/Greeter/GetStream"
    Greeter_PostStream_FullMethodName = "/Greeter/PostStream"
    Greeter_AllStream_FullMethodName  = "/Greeter/AllStream"
)

// GreeterClient is the client API for Greeter service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type GreeterClient interface {
    GetStream(ctx context.Context, in *StreamReqDate, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamResData], error)
    PostStream(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[StreamReqDate, StreamResData], error)
    AllStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[StreamReqDate, StreamResData], error)
}

type greeterClient struct {
    cc grpc.ClientConnInterface
}

func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient {
    return &greeterClient{cc}
}

func (c *greeterClient) GetStream(ctx context.Context, in *StreamReqDate, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamResData], error) {
    cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
    stream, err := c.cc.NewStream(ctx, &Greeter_ServiceDesc.Streams[0], Greeter_GetStream_FullMethodName, cOpts...)
    if err != nil {
        return nil, err
    }
    x := &grpc.GenericClientStream[StreamReqDate, StreamResData]{ClientStream: stream}
    if err := x.ClientStream.SendMsg(in); err != nil {
        return nil, err
    }
    if err := x.ClientStream.CloseSend(); err != nil {
        return nil, err
    }
    return x, nil
}

// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Greeter_GetStreamClient = grpc.ServerStreamingClient[StreamResData]

func (c *greeterClient) PostStream(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[StreamReqDate, StreamResData], error) {
    cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
    stream, err := c.cc.NewStream(ctx, &Greeter_ServiceDesc.Streams[1], Greeter_PostStream_FullMethodName, cOpts...)
    if err != nil {
        return nil, err
    }
    x := &grpc.GenericClientStream[StreamReqDate, StreamResData]{ClientStream: stream}
    return x, nil
}

// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Greeter_PostStreamClient = grpc.ClientStreamingClient[StreamReqDate, StreamResData]

func (c *greeterClient) AllStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[StreamReqDate, StreamResData], error) {
    cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
    stream, err := c.cc.NewStream(ctx, &Greeter_ServiceDesc.Streams[2], Greeter_AllStream_FullMethodName, cOpts...)
    if err != nil {
        return nil, err
    }
    x := &grpc.GenericClientStream[StreamReqDate, StreamResData]{ClientStream: stream}
    return x, nil
}

// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Greeter_AllStreamClient = grpc.BidiStreamingClient[StreamReqDate, StreamResData]

// GreeterServer is the server API for Greeter service.
// All implementations must embed UnimplementedGreeterServer
// for forward compatibility.
type GreeterServer interface {
    GetStream(*StreamReqDate, grpc.ServerStreamingServer[StreamResData]) error
    PostStream(grpc.ClientStreamingServer[StreamReqDate, StreamResData]) error
    AllStream(grpc.BidiStreamingServer[StreamReqDate, StreamResData]) error
    mustEmbedUnimplementedGreeterServer()
}

// UnimplementedGreeterServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedGreeterServer struct{}

func (UnimplementedGreeterServer) GetStream(*StreamReqDate, grpc.ServerStreamingServer[StreamResData]) error {
    return status.Error(codes.Unimplemented, "method GetStream not implemented")
}
func (UnimplementedGreeterServer) PostStream(grpc.ClientStreamingServer[StreamReqDate, StreamResData]) error {
    return status.Error(codes.Unimplemented, "method PostStream not implemented")
}
func (UnimplementedGreeterServer) AllStream(grpc.BidiStreamingServer[StreamReqDate, StreamResData]) error {
    return status.Error(codes.Unimplemented, "method AllStream not implemented")
}
func (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {}
func (UnimplementedGreeterServer) testEmbeddedByValue()                 {}

// UnsafeGreeterServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to GreeterServer will
// result in compilation errors.
type UnsafeGreeterServer interface {
    mustEmbedUnimplementedGreeterServer()
}

func RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) {
    // If the following call panics, it indicates UnimplementedGreeterServer was
    // embedded by pointer and is nil.  This will cause panics if an
    // unimplemented method is ever invoked, so we test this at initialization
    // time to prevent it from happening at runtime later due to I/O.
    if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
        t.testEmbeddedByValue()
    }
    s.RegisterService(&Greeter_ServiceDesc, srv)
}

func _Greeter_GetStream_Handler(srv interface{}, stream grpc.ServerStream) error {
    m := new(StreamReqDate)
    if err := stream.RecvMsg(m); err != nil {
        return err
    }
    return srv.(GreeterServer).GetStream(m, &grpc.GenericServerStream[StreamReqDate, StreamResData]{ServerStream: stream})
}

// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Greeter_GetStreamServer = grpc.ServerStreamingServer[StreamResData]

func _Greeter_PostStream_Handler(srv interface{}, stream grpc.ServerStream) error {
    return srv.(GreeterServer).PostStream(&grpc.GenericServerStream[StreamReqDate, StreamResData]{ServerStream: stream})
}

// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Greeter_PostStreamServer = grpc.ClientStreamingServer[StreamReqDate, StreamResData]

func _Greeter_AllStream_Handler(srv interface{}, stream grpc.ServerStream) error {
    return srv.(GreeterServer).AllStream(&grpc.GenericServerStream[StreamReqDate, StreamResData]{ServerStream: stream})
}

// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Greeter_AllStreamServer = grpc.BidiStreamingServer[StreamReqDate, StreamResData]

// Greeter_ServiceDesc is the grpc.ServiceDesc for Greeter service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Greeter_ServiceDesc = grpc.ServiceDesc{
    ServiceName: "Greeter",
    HandlerType: (*GreeterServer)(nil),
    Methods:     []grpc.MethodDesc{},
    Streams: []grpc.StreamDesc{
        {
            StreamName:    "GetStream",
            Handler:       _Greeter_GetStream_Handler,
            ServerStreams: true,
        },
        {
            StreamName:    "PostStream",
            Handler:       _Greeter_PostStream_Handler,
            ClientStreams: true,
        },
        {
            StreamName:    "AllStream",
            Handler:       _Greeter_AllStream_Handler,
            ServerStreams: true,
            ClientStreams: true,
        },
    },
    Metadata: "stream.proto",
}
View Code

 

查看生成的stream.pb文件

// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
//     protoc-gen-go v1.36.11
//     protoc        v7.35.1
// source: stream.proto

package v1

import (
    protoreflect "google.golang.org/protobuf/reflect/protoreflect"
    protoimpl "google.golang.org/protobuf/runtime/protoimpl"
    reflect "reflect"
    sync "sync"
    unsafe "unsafe"
)

const (
    // Verify that this generated code is sufficiently up-to-date.
    _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
    // Verify that runtime/protoimpl is sufficiently up-to-date.
    _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)

type StreamReqDate struct {
    state         protoimpl.MessageState `protogen:"open.v1"`
    Data          string                 `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
    unknownFields protoimpl.UnknownFields
    sizeCache     protoimpl.SizeCache
}

func (x *StreamReqDate) Reset() {
    *x = StreamReqDate{}
    mi := &file_stream_proto_msgTypes[0]
    ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
    ms.StoreMessageInfo(mi)
}

func (x *StreamReqDate) String() string {
    return protoimpl.X.MessageStringOf(x)
}

func (*StreamReqDate) ProtoMessage() {}

func (x *StreamReqDate) ProtoReflect() protoreflect.Message {
    mi := &file_stream_proto_msgTypes[0]
    if x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}

// Deprecated: Use StreamReqDate.ProtoReflect.Descriptor instead.
func (*StreamReqDate) Descriptor() ([]byte, []int) {
    return file_stream_proto_rawDescGZIP(), []int{0}
}

func (x *StreamReqDate) GetData() string {
    if x != nil {
        return x.Data
    }
    return ""
}

type StreamResData struct {
    state         protoimpl.MessageState `protogen:"open.v1"`
    Data          string                 `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
    unknownFields protoimpl.UnknownFields
    sizeCache     protoimpl.SizeCache
}

func (x *StreamResData) Reset() {
    *x = StreamResData{}
    mi := &file_stream_proto_msgTypes[1]
    ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
    ms.StoreMessageInfo(mi)
}

func (x *StreamResData) String() string {
    return protoimpl.X.MessageStringOf(x)
}

func (*StreamResData) ProtoMessage() {}

func (x *StreamResData) ProtoReflect() protoreflect.Message {
    mi := &file_stream_proto_msgTypes[1]
    if x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}

// Deprecated: Use StreamResData.ProtoReflect.Descriptor instead.
func (*StreamResData) Descriptor() ([]byte, []int) {
    return file_stream_proto_rawDescGZIP(), []int{1}
}

func (x *StreamResData) GetData() string {
    if x != nil {
        return x.Data
    }
    return ""
}

var File_stream_proto protoreflect.FileDescriptor

const file_stream_proto_rawDesc = "" +
    "\n" +
    "\fstream.proto\"#\n" +
    "\rStreamReqDate\x12\x12\n" +
    "\x04data\x18\x01 \x01(\tR\x04data\"#\n" +
    "\rStreamResData\x12\x12\n" +
    "\x04data\x18\x01 \x01(\tR\x04data2\x99\x01\n" +
    "\aGreeter\x12-\n" +
    "\tGetStream\x12\x0e.StreamReqDate\x1a\x0e.StreamResData0\x01\x12.\n" +
    "\n" +
    "PostStream\x12\x0e.StreamReqDate\x1a\x0e.StreamResData(\x01\x12/\n" +
    "\tAllStream\x12\x0e.StreamReqDate\x1a\x0e.StreamResData(\x010\x01B!Z\x1f../../../common/stream/proto/v1b\x06proto3"

var (
    file_stream_proto_rawDescOnce sync.Once
    file_stream_proto_rawDescData []byte
)

func file_stream_proto_rawDescGZIP() []byte {
    file_stream_proto_rawDescOnce.Do(func() {
        file_stream_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_stream_proto_rawDesc), len(file_stream_proto_rawDesc)))
    })
    return file_stream_proto_rawDescData
}

var file_stream_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_stream_proto_goTypes = []any{
    (*StreamReqDate)(nil), // 0: StreamReqDate
    (*StreamResData)(nil), // 1: StreamResData
}
var file_stream_proto_depIdxs = []int32{
    0, // 0: Greeter.GetStream:input_type -> StreamReqDate
    0, // 1: Greeter.PostStream:input_type -> StreamReqDate
    0, // 2: Greeter.AllStream:input_type -> StreamReqDate
    1, // 3: Greeter.GetStream:output_type -> StreamResData
    1, // 4: Greeter.PostStream:output_type -> StreamResData
    1, // 5: Greeter.AllStream:output_type -> StreamResData
    3, // [3:6] is the sub-list for method output_type
    0, // [0:3] is the sub-list for method input_type
    0, // [0:0] is the sub-list for extension type_name
    0, // [0:0] is the sub-list for extension extendee
    0, // [0:0] is the sub-list for field type_name
}

func init() { file_stream_proto_init() }
func file_stream_proto_init() {
    if File_stream_proto != nil {
        return
    }
    type x struct{}
    out := protoimpl.TypeBuilder{
        File: protoimpl.DescBuilder{
            GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
            RawDescriptor: unsafe.Slice(unsafe.StringData(file_stream_proto_rawDesc), len(file_stream_proto_rawDesc)),
            NumEnums:      0,
            NumMessages:   2,
            NumExtensions: 0,
            NumServices:   1,
        },
        GoTypes:           file_stream_proto_goTypes,
        DependencyIndexes: file_stream_proto_depIdxs,
        MessageInfos:      file_stream_proto_msgTypes,
    }.Build()
    File_stream_proto = out.File
    file_stream_proto_goTypes = nil
    file_stream_proto_depIdxs = nil
}
View Code

 go 控制grpc的metadata

gRPC让我们可以像本地调用一样实现远程调用,对于每一次的RPC调用中,都可能会有一些有用的数据,而这些数据就可以通过metadata来传递。metadata是以key-value的形式存储数据的,其中key是string类型,而value是[]string,即一个字符串数组类型。metadata使得client和server能够为对方提供关于本次调用的一些信息,就像一次http请求的RequestHeader和ResponseHeader一样。http中header的生命周周期是一次http请求,那么metadata的生命周期就是一次RPC调用。

新建matedata

MD 类型实际上是map,key是string,value是string类型的slice。

type MD map[string][]string

创建的时候可以像创建普通的map类型一样使用new关键字进行创建:

//第一种方式
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",
)

 2发送

md := metadata.Pairs("key", "val")

// 新建一个有 metadata 的 context
ctx := metadata.NewOutgoingContext(context.Background(), md)

// 单向 RPC
response, err := client.SomeRPC(ctx, someRequest)

 3.接收

func (s *server) SomeRPC(ctx context.Context, in *pb.SomeRequest) (*pb.SomeResponse, err) {
    md, ok := metadata.FromIncomingContext(ctx)
    // do something with metadata
}

  proto文件引入另一个proto文件

hello.proto 文件;注意大小写一致

syntax = "proto3";
import "base.proto";
import "google/protobuf/empty.proto";
option go_package = ".;proto";
service Greeter {
    rpc SayHello(HelloRequest) returns(HelloReply);
    rpc Ping(Empty) returns(Pong);
}
message HelloRequest {
    string url = 1;
    string name = 2;
}

message HelloReply {
    string message  =1;
    //嵌套
    message Result {
    string url=1;
    string name =2;
    }
    repeated Result data =2;
}

  base.proto 文件注意包名

syntax = "proto3";
option go_package = ".;proto";//需要指定包,否则不知道哪个包下的
message Empty {
}
message Pong {
    string id =1;
}



PS D:\golang\goproject\src\lnhgo> cd protobuf\day3\grpc_proto_test\proto
PS D:\golang\goproject\src\lnhgo\protobuf\day3\grpc_proto_test\proto> protoc --go_out=. --go-grpc_out=. Hello.proto

  引入互联网公共文件与本地文件

syntax = "proto3";
option go_package = ".;proto";
import "base.proto";//本地文件
import "google/protobuf/empty.proto";//公共文件
service Greeter {
    rpc SayHello (HelloRequest) returns (HelloReply);
    rpc Ping (google.protobuf.Empty) returns (Pong);
}
message HelloRequest {
    string url =1;
    string name =2;
}
message HelloReply {
    string message =1;
}

  base.protu文件

syntax = "proto3";
option go_package = ".;proto";//需要指定包,否则不知道哪个包下的
message Empty {
}
message Pong {
    string id =1;
}
执行命令
PS D:\golang\goproject\src\lnhgo\protobuf\day3\grpc_proto_test\proto> protoc --go_out=. --go-grpc_out=. Hello.proto base.proto

  嵌套message 的实现

 

syntax = "proto3";
option go_package = ".;proto";
import "base.proto";//本地文件
import "google/protobuf/empty.proto";//公共文件
service Greeter {
    rpc SayHello (HelloRequest) returns (HelloReply);
    rpc Ping (google.protobuf.Empty) returns (Pong);
}
message HelloRequest {
    string url =1;
    string name =2;
}

message HelloReply {
    string message =1;
    //嵌套
    message Result {
        string name=1;
        string url =2;
    }
    repeated Result data=2;
}

PS D:\golang\goproject\src\lnhgo\protobuf\day3\grpc_proto_test\proto> protoc --go_out=. --go-grpc_out=. Hello.proto base.proto

  嵌套对象的使用

package main
import (
	"lnhgo/protobuf/day3/grpc_proto_test/proto"
)
func main(){
	proto.HelloReply_Result{}//嵌套对象的使用
	proto.Pong{}
}

  枚举类型

syntax = "proto3";
import "base.proto";
import "google/protobuf/empty.proto";
option go_package = ".;proto";
service Greeter {
    rpc SayHello(HelloRequest) returns(HelloReply);
    rpc Ping(empty) returns(Pong);
}
enum Gender {// 枚举类型
    MALE =1;
    FEMALE =2;

}
message HelloRequest {
    string url = 1;
    string name = 2;
    Gender g =3;//枚举类型
}


message HelloReply {
    string message  =1;
}

  map 类型

syntax = "proto3";
import "base.proto";
//import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
option go_package = ".;proto";
service Greeter {
    rpc SayHello(HelloRequest) returns(HelloReply);
    rpc Ping(Empty) returns(Pong);
}
enum Gender {// 枚举类型
    MALE =0;
    FEMALE =1;

}
message HelloRequest {
    string url = 1;
    string name = 2;
    Gender g =3;//枚举类型
    map<string,string> mp=4; //map
    google.protobuf.Timestamp addTime =5;
}


message HelloReply {
    string message  =1;
}

  时间戳

syntax = "proto3";
import "base.proto";
//import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
option go_package = ".;proto";
service Greeter {
    rpc SayHello(HelloRequest) returns(HelloReply);
    rpc Ping(Empty) returns(Pong);
}
enum Gender {// 枚举类型
    MALE =0;
    FEMALE =1;

}
message HelloRequest {
    string url = 1;
    string name = 2;
    Gender g =3;//枚举类型
    map<string,string> mp=4;
    google.protobuf.Timestamp addTime =5;//时间戳
}


message HelloReply {
    string message  =1;
}

  go控制grpc的metadata

      gRPC让我们可以像本地调用一样实现远程调用,对于每一次的RPC调用中,都可能会有一些有用的数据,而这些数据就可以通过metadata来传递。metadata是以key-value的形式存储数据的,其中key是string类型,而value是[]string,即一个字符串数组类型。metadata使得client和server能够为对方提供关于本次调用的一些信息,就像一次http请求的RequestHeader和ResponseHeader一样。http中header的生命周周期是一次http请求,那么metadata的生命周期就是一次RPC调用。

示例

client

package main

import (
	"context"
	"fmt"
	"lnhgo/metadata_test/proto"
	//"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/metadata"
)

func main() {
	conn, err := grpc.NewClient(
    "127.0.0.1:8080",
    grpc.WithTransportCredentials(insecure.NewCredentials()),
)
	if err !=nil{
		panic("连接失败")
	}
	defer conn.Close()
	c:=proto.NewGreeterClient(conn)
	//timestampFormat := ""
	//md := metadata.Pairs("timestamp", time.Now().Format(timestampFormat))
	md := metadata.New(map[string]string{
		"name":"bobby",
		"pasword":"imooc",
	})
	ctx := metadata.NewOutgoingContext(context.Background(), md)
	//r,err:=c.SayHello(context.Background(),&proto.HelloRequest{Name: "chenxi"})
	//r,err:=c.SayHello(context.Background(),&proto.HelloRequest{})
	r,err:=c.SayHello(ctx,&proto.HelloRequest{Name: "bobby"})

	if err != nil{
		panic("调用失败")
	}
	fmt.Println(r.Message)
}

  server

package main

import (
	"context"
	"fmt"
	"lnhgo/metadata_test/proto"
	"net"

	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
)

type Server struct{
	proto.UnimplementedGreeterServer
}

func (s *Server) SayHello(c context.Context,request *proto.HelloRequest)(*proto.HelloReply,error){
	//matadata := nil
	md,ok:=metadata.FromIncomingContext(c)
	if ok {
		fmt.Println("get metadata error")
	}
	for key,val:=range md{
		fmt.Println(key,val)
	}
	if name,ok:=md["name"];ok{
		fmt.Println(name)
	}
	return &proto.HelloReply{
		Message: "hello "+request.Name,
	},nil
}
//func (s *Server)mustEmbedUnimplementedGreeterServer(){}
func main(){
	g:=grpc.NewServer()
	proto.RegisterGreeterServer(g,&Server{})
	lis,err:=net.Listen("tcp","0.0.0.0:8080")
	if err !=nil {
		panic("监听失败")
	}
	err=g.Serve(lis)
	if err !=nil {
		panic("启动失败")
	}
}

  执行结果

服务端启动
PS D:\golang\goproject\src\lnhgo> go run protobuf\day2\server\server.go
客户端启动
PS D:\golang\goproject\src\lnhgo> go run protobuf\day2\client\client.go
hello bobby
服务终端显示
get metadata error
:authority [127.0.0.1:8080]
content-type [application/grpc]
user-agent [grpc-go/1.82.1]
name [bobby]
pasword [imooc]
[bobby]

  grpc 拦截器

server 端拦截器

package main

import (
	"context"
	"fmt"
	"lnhgo/grpc_interpretor/proto"
	"net"

	"google.golang.org/grpc"
	//"google.golang.org/grpc/metadata"
)

type Server struct{
	proto.UnimplementedGreeterServer
}

func (s *Server) SayHello(c context.Context,request *proto.HelloRequest)(*proto.HelloReply,error){
	//matadata := nil
	// md,ok:=metadata.FromIncomingContext(c)
	// if ok {
	// 	fmt.Println("get metadata error")
	// }
	// for key,val:=range md{
	// 	fmt.Println(key,val)
	// }
	// if name,ok:=md["name"];ok{
	// 	fmt.Println(name)
	// }
	return &proto.HelloReply{
		Message: "hello "+request.Name,
	},nil
}
//func (s *Server)mustEmbedUnimplementedGreeterServer(){}

func main(){
	interceptor:=func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error){
		fmt.Println("接收到请求")
		res,err:= handler(ctx,req)
		fmt.Println("请求完成")
		return res ,err 
	}
	opt:= grpc.UnaryInterceptor(interceptor)//server 拦截器
	g:=grpc.NewServer(opt)
	proto.RegisterGreeterServer(g,&Server{})
	lis,err:=net.Listen("tcp","0.0.0.0:8080")
	if err !=nil {
		panic("监听失败")
	}
	err=g.Serve(lis)
	if err !=nil {
		panic("启动失败")
	}
}


PS D:\golang\goproject\src\lnhgo> go run grpc_interpretor\server\server.go

  测试代码

package main

import (
	"context"
	"fmt"
	"lnhgo/metadata_test/proto"
	//"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/metadata"
)

func main() {
	conn, err := grpc.NewClient(
    "127.0.0.1:8080",
    grpc.WithTransportCredentials(insecure.NewCredentials()),
)
	if err !=nil{
		panic("连接失败")
	}
	defer conn.Close()
	c:=proto.NewGreeterClient(conn)
	//timestampFormat := ""
	//md := metadata.Pairs("timestamp", time.Now().Format(timestampFormat))
	md := metadata.New(map[string]string{
		"name":"bobby",
		"pasword":"imooc",
	})
	ctx := metadata.NewOutgoingContext(context.Background(), md)
	//r,err:=c.SayHello(context.Background(),&proto.HelloRequest{Name: "chenxi"})
	//r,err:=c.SayHello(context.Background(),&proto.HelloRequest{})
	r,err:=c.SayHello(ctx,&proto.HelloRequest{Name: "bobby"})

	if err != nil{
		panic("调用失败")
	}
	fmt.Println(r.Message)
}

PS D:\golang\goproject\src\lnhgo> go run metadata_test\client\client.go
hello bobby

  服务端显示

接收到请求
请求完成

  client 拦截器(下面代码运行测试用例是,服务端处于运行状态server代码跟上面一致)

package main

import (
	"context"
	"fmt"
	"lnhgo/metadata_test/proto"
	"time"

	//"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/metadata"
)

func main() {
	interceptor:=func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error{
		fmt.Println("==========进入客户端拦截器==========")
    	
		fmt.Println("method:", method)
		start:= time.Now()
		err:=invoker(ctx,method,req,reply,cc,opts...)
		fmt.Printf("耗时:%s\n",time.Since(start))
		return err

	}
	ops:=grpc.WithUnaryInterceptor(interceptor)
	conn, err := grpc.NewClient(
    "127.0.0.1:8080",
    grpc.WithTransportCredentials(insecure.NewCredentials()),
	ops,
)
	if err !=nil{
		panic("连接失败")
	}
	defer conn.Close()
	c:=proto.NewGreeterClient(conn)
	md := metadata.New(map[string]string{
		"name":"bobby",
		"pasword":"imooc",
	})
	ctx := metadata.NewOutgoingContext(context.Background(), md)
	r,err:=c.SayHello(ctx,&proto.HelloRequest{Name: "bobby"})

	if err != nil{
		panic("调用失败")
	}
	fmt.Println(r.Message)
}
测试
PS D:\golang\goproject\src\lnhgo> go run grpc_interpretor\client\client.go
==========进入客户端拦截器==========
method: /Greeter/SayHello
耗时:2.8415ms
hello bobby

  通过metadata实现grpc的认证

client 

package main

import (
	"context"
	"fmt"
	"lnhgo/grpc_token_auth_test/proto"
	"time"

	//"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/metadata"
)

func main() {
	interceptor:=func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error{
		fmt.Println("==========进入客户端拦截器==========")
    	
		fmt.Println("method:", method)
		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("耗时:%s\n",time.Since(start))
		return err

	}
	ops:=grpc.WithUnaryInterceptor(interceptor)
	conn, err := grpc.NewClient(
    "127.0.0.1:8080",
    grpc.WithTransportCredentials(insecure.NewCredentials()),
	ops,
)
	if err !=nil{
		panic("连接失败")
	}
	defer conn.Close()
	c:=proto.NewGreeterClient(conn)
	md := metadata.New(map[string]string{
		"name":"bobby",
		"pasword":"imooc",
	})
	ctx := metadata.NewOutgoingContext(context.Background(), md)
	r,err:=c.SayHello(ctx,&proto.HelloRequest{Name: "bobby"})

	if err != nil{
		panic("调用失败")
	}
	fmt.Println(r.Message)
}

  server 

package main

import (
	"context"
	"fmt"
	"lnhgo/grpc_token_auth_test/proto"
	"net"

	//"google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"//如果没有status 请执行下载命令go get google.golang.org/grpc 和 go get google.golang.org/grpc/status
)

type Server struct{
	proto.UnimplementedGreeterServer
}

func (s *Server) SayHello(c context.Context,request *proto.HelloRequest)(*proto.HelloReply,error){
	//matadata := nil
	// md,ok:=metadata.FromIncomingContext(c)
	// if ok {
	// 	fmt.Println("get metadata error")
	// }
	// for key,val:=range md{
	// 	fmt.Println(key,val)
	// }
	// if name,ok:=md["name"];ok{
	// 	fmt.Println(name)
	// }
	return &proto.HelloReply{
		Message: "hello "+request.Name,
	},nil
}
//func (s *Server)mustEmbedUnimplementedGreeterServer(){}

func main(){
	interceptor:=func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error){
		fmt.Println("接收到请求")
		md,ok:=metadata.FromIncomingContext(ctx)
		fmt.Println(md)
		if !ok {
			return resp,status.Error(codes.Unauthenticated,"无token认证信息")
			//fmt.Println("get metadata error")
		}
		var (
			appid string
			appkey string
		)
		if va1,ok:=md["appid"];ok {
			appid = va1[0]
			fmt.Println(appid)
		}
		if va2,ok:=md["appkey"];ok {
			appkey = va2[0]
			fmt.Println(appkey)
		}
		if appid != "101010"|| appkey != "i am key"{
			fmt.Println("验证失败")
			return resp,status.Error(codes.Unauthenticated,"认证信息错误")
		}
		// if nameSlice,ok:=md["appid"];ok{
		// 	fmt.Println(nameSlice)
		// 	for i,e:=range nameSlice{
		// 		fmt.Println(i,e)
		// 	}
		// }
		res,err:= handler(ctx,req)
		fmt.Println("请求完成")
		return res ,err 
	}
	opt:= grpc.UnaryInterceptor(interceptor)//server 拦截器
	g:=grpc.NewServer(opt)
	proto.RegisterGreeterServer(g,&Server{})
	lis,err:=net.Listen("tcp","0.0.0.0:8080")
	if err !=nil {
		panic("监听失败")
	}
	err=g.Serve(lis)
	if err !=nil {
		panic("启动失败")
	}
}

  启动

server 启动
PS D:\golang\goproject\src\lnhgo> go run grpc_token_auth_test\server\server.go
client 测试启动
PS D:\golang\goproject\src\lnhgo> go run grpc_token_auth_test\client\client.go
==========进入客户端拦截器==========
method: /Greeter/SayHello
耗时:3.1413ms
hello bobby
观察server 的输出

接收到请求
map[:authority:[127.0.0.1:8080] appid:[101010] appkey:[i am key] content-type:[application/grpc] user-agent:[grpc-go/1.83.2]]
101010
i am key
请求完成

  客户端传递认证方式2

 

package main

import (
	"context"
	"fmt"
	"lnhgo/grpc_token_auth_test/proto"
	//"time"

	//"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/metadata"
)
type customCredential struct{}
func (c customCredential)GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error){
	return map[string]string{
			"appid":"101010",
			"appkey":"i am key",
	},nil
}
func (c customCredential)RequireTransportSecurity() bool{
	return false
}

func main() {
	// interceptor:=func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error{
	// 	fmt.Println("==========进入客户端拦截器==========")
    	
	// 	fmt.Println("method:", method)
	// 	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("耗时:%s\n",time.Since(start))
	// 	return err

	// }
	
	// ops:=grpc.WithUnaryInterceptor(interceptor)
	conn, err := grpc.NewClient(
    "127.0.0.1:8080",
    grpc.WithTransportCredentials(insecure.NewCredentials()),
	//ops,
	grpc.WithPerRPCCredentials(customCredential{}),
)
	if err !=nil{
		panic("连接失败")
	}
	defer conn.Close()
	c:=proto.NewGreeterClient(conn)
	md := metadata.New(map[string]string{
		"name":"bobby",
		"pasword":"imooc",
	})
	ctx := metadata.NewOutgoingContext(context.Background(), md)
	r,err:=c.SayHello(ctx,&proto.HelloRequest{Name: "bobby"})

	if err != nil{
		panic("调用失败")
	}
	fmt.Println(r.Message)
}
测试
PS D:\golang\goproject\src\lnhgo> go run grpc_token_auth_test\client\client.go
hello bobby

  客户端传递认证方式3+ 拦截

package main

import (
	"context"
	"fmt"
	"lnhgo/grpc_token_auth_test/proto"
	"time"

	//"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/metadata"
)
type customCredential struct{}
func (c customCredential)GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error){
	return map[string]string{
			"appid":"101010",
			"appkey":"i am key",
	},nil
}
func (c customCredential)RequireTransportSecurity() bool{
	return false
}

func main() {
	interceptor:=func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error{
		fmt.Println("==========进入客户端拦截器==========")
    	
		fmt.Println("method:", method)
		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("耗时:%s\n",time.Since(start))
		return err

	}
	
	ops:=grpc.WithUnaryInterceptor(interceptor)
	conn, err := grpc.NewClient(
    "127.0.0.1:8080",
    grpc.WithTransportCredentials(insecure.NewCredentials()),
	ops,
	grpc.WithPerRPCCredentials(customCredential{}),
)
	if err !=nil{
		panic("连接失败")
	}
	defer conn.Close()
	c:=proto.NewGreeterClient(conn)
	md := metadata.New(map[string]string{
		"name":"bobby",
		"pasword":"imooc",
	})
	ctx := metadata.NewOutgoingContext(context.Background(), md)
	r,err:=c.SayHello(ctx,&proto.HelloRequest{Name: "bobby"})

	if err != nil{
		panic("调用失败")
	}
	fmt.Println(r.Message)
}
执行结果
PS D:\golang\goproject\src\lnhgo> go run grpc_token_auth_test\client\client.go
==========进入客户端拦截器==========
method: /Greeter/SayHello
耗时:2.9185ms
hello bobby

  grpc 的验证器

Windows安装插件

D:\goproject\bin>go install github.com/envoyproxy/protoc-gen-validate@latest
go: downloading github.com/envoyproxy/protoc-gen-validate v1.3.3
go: downloading github.com/lyft/protoc-gen-star/v2 v2.0.4
go: downloading github.com/iancoleman/strcase v0.3.0
go: downloading golang.org/x/tools v0.41.0
go: downloading github.com/spf13/afero v1.15.0
go: downloading golang.org/x/text v0.33.0
go: downloading golang.org/x/sync v0.19.0
go: downloading golang.org/x/mod v0.32.0

  1.新建validate.proto文件内容从此处拷贝

2.准备proto文件

syntax = "proto3";

import "validate.proto";
option go_package=".;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}$"}];

}

  下载依赖

PS D:\golang\goproject\src\lnhgo\grpc_validate_test\proto> go get github.com/envoyproxy/protoc-gen-validate@latest
go: downloading golang.org/x/tools v0.48.0
go: downloading golang.org/x/mod v0.38.0
go: downloading golang.org/x/sync v0.22.0
go: added github.com/iancoleman/strcase v0.3.0
go: added github.com/lyft/protoc-gen-star/v2 v2.0.4
go: added github.com/spf13/afero v1.15.0

  生成文件

PS D:\golang\goproject\src\lnhgo\grpc_validate_test\proto> protoc -I .  --go_out=. --go-grpc_out=. --validate_out="lang=go:." helloworld.proto

  server

package main

import (
	"context"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"net"

	"google.golang.org/grpc"

	"lnhgo/grpc_validate_test/proto"
)


type Server struct{
	proto.UnimplementedGreeterServer
	
}
//func (s *Server) mustEmbedUnimplementedGreeterServer(){}
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(){
	// p:=new(proto.Person)
	// p.Id=1000
	// err:=p.Validate()

	// if err != nil{
	// 	panic(err)
	// }
	var interceptor grpc.UnaryServerInterceptor
	interceptor = 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.ServerOption
	opts = 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())
	}
}

  启动server

PS D:\golang\goproject\src\lnhgo> go run grpc_validate_test\server\server.go

  client文件

package  main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"lnhgo/grpc_validate_test/proto"
)

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: 1000,
		Email: "bobby@imocc.com",
		Mobile: "18888888843",
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(rsp.Id)
}

  客户端启动

PS D:\golang\goproject\src\lnhgo> go run grpc_validate_test\client\client.go
32

  grpc 的异常处理

grpc 的状态码

go 的异常处理

server

package main

import (
	"context"
	"lnhgo/grpc_error_test/proto"
	"net"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

type Server struct{
	proto.UnimplementedGreeterServer
}

func (s *Server) SayHello(c context.Context,request *proto.HelloRequest)(*proto.HelloReply,error){
	// return &proto.HelloReply{
	// 	Message: "hello "+request.Name,
	// },nil
	return nil,status.Errorf(codes.NotFound,"记录未找到%s",request.Name)//错误处理
}
//func (s *Server)mustEmbedUnimplementedGreeterServer(){}
func main(){
	g:=grpc.NewServer()
	proto.RegisterGreeterServer(g,&Server{})
	lis,err:=net.Listen("tcp","0.0.0.0:8080")
	if err !=nil {
		panic("监听失败")
	}
	err=g.Serve(lis)
	if err !=nil {
		panic("启动失败")
	}
}
启动
PS D:\golang\goproject\src\lnhgo> go run grpc_error_test\server\server.go

  client 文件

package main

import (
	"context"
	"fmt"
	"lnhgo/grpc_error_test/proto"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/status"
)

func main() {
	conn, err := grpc.NewClient(
    "127.0.0.1:8080",
    grpc.WithTransportCredentials(insecure.NewCredentials()),
)
	if err !=nil{
		panic("连接失败")
	}
	defer conn.Close()
	c:=proto.NewGreeterClient(conn)
	_,err=c.SayHello(context.Background(),&proto.HelloRequest{Name: "chenxi"})
	if err != nil{
		st, ok := status.FromError(err)
		if !ok {
    // Error was not a status error
			panic("解析error 错误")
		}
		fmt.Println(st.Message())
		fmt.Println(st.Code())
		// panic(err)
	}
	//fmt.Println(r.Message)
}
执行结果
PS D:\golang\goproject\src\lnhgo> go run grpc_error_test\client\client.go
记录未找到chenxi
NotFound

  grpc 的超时机制

server

package main

import (
	"context"
	"lnhgo/grpc_error_test/proto"
	"net"
	"time"

	"google.golang.org/grpc"
	//"google.golang.org/grpc/codes"
	//"google.golang.org/grpc/status"
)

type Server struct{
	proto.UnimplementedGreeterServer
}

func (s *Server) SayHello(c context.Context,request *proto.HelloRequest)(*proto.HelloReply,error){
	time.Sleep(5*time.Second) // 休眠5秒
	return &proto.HelloReply{
		Message: "hello "+request.Name,
	},nil
	//return nil,status.Errorf(codes.NotFound,"记录未找到%s",request.Name)//错误处理
}
//func (s *Server)mustEmbedUnimplementedGreeterServer(){}
func main(){
	g:=grpc.NewServer()
	proto.RegisterGreeterServer(g,&Server{})
	lis,err:=net.Listen("tcp","0.0.0.0:8080")
	if err !=nil {
		panic("监听失败")
	}
	err=g.Serve(lis)
	if err !=nil {
		panic("启动失败")
	}
}
启动
PS D:\golang\goproject\src\lnhgo> go run grpc_error_test\server\server.go

  client

package main

import (
	"context"
	"fmt"
	"lnhgo/grpc_error_test/proto"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/status"
)

func main() {
	conn, err := grpc.NewClient(
    "127.0.0.1:8080",
    grpc.WithTransportCredentials(insecure.NewCredentials()),
)
	if err !=nil{
		panic("连接失败")
	}
	defer conn.Close()
	c:=proto.NewGreeterClient(conn)
	ctx,_:= context.WithTimeout(context.Background(),time.Second*3) //设置调用超时时间为3秒
	_,err=c.SayHello(ctx,&proto.HelloRequest{Name: "chenxi"})
	if err != nil{
		st, ok := status.FromError(err)
		if !ok {
    // Error was not a status error
			panic("解析error 错误")
		}
		fmt.Println(st.Message())
		fmt.Println(st.Code())
		// panic(err)
	}
	//fmt.Println(r.Message)
}
启动
PS D:\golang\goproject\src\lnhgo> go run grpc_error_test\client\client.go
context deadline exceeded
DeadlineExceeded

  

 

 

 

 

 

 

 

 

  

 

 

 

 

 

 

posted @ 2026-08-27 13:25  烟雨楼台,行云流水  阅读(5)  评论(0)    收藏  举报