Go如何写一个通用grpc接口
我来为您详细讲解如何在 Go 中编写通用 gRPC 接口涵盖从基础到高级的设计模式。1. 基础通用接口设计1.1 标准 gRPC 服务定义proto// api.protosyntax proto3;package api;option go_package github.com/example/api;// 通用请求/响应包装器message GenericRequest {string service 1; // 服务名string method 2; // 方法名bytes payload 3; // 序列化的请求数据JSON/Protobufmapstring, string metadata 4; // 额外元数据}message GenericResponse {int32 code 1; // 业务状态码string message 2; // 状态信息bytes data 3; // 响应数据mapstring, string metadata 4;}// 通用服务service GenericAPI {rpc Call(GenericRequest) returns (GenericResponse);rpc StreamCall(stream GenericRequest) returns (stream GenericResponse);}1.2 服务端实现反射注册表模式package mainimport (contextencoding/jsonfmtreflectgoogle.golang.org/grpcgoogle.golang.org/grpc/codesgoogle.golang.org/grpc/statusgoogle.golang.org/protobuf/types/known/anypb)// Handler 通用处理函数类型type Handler func(ctx context.Context, req interface{}) (interface{}, error)// ServiceRegistry 服务注册表type ServiceRegistry struct {handlers map[string]Handler // key: Service.Method}func NewServiceRegistry() *ServiceRegistry {return ServiceRegistry{handlers: make(map[string]Handler),}}// Register 注册服务方法func (r *ServiceRegistry) Register(service, method string, handler Handler) {key : fmt.Sprintf(%s.%s, service, method)r.handlers[key] handler}// Get 获取处理器func (r *ServiceRegistry) Get(service, method string) (Handler, bool) {key : fmt.Sprintf(%s.%s, service, method)h, ok : r.handlers[key]return h, ok}// GenericServer 通用gRPC服务器type GenericServer struct {registry *ServiceRegistryUnimplementedGenericAPIServer}func NewGenericServer(registry *ServiceRegistry) *GenericServer {return GenericServer{registry: registry}}// Call 实现通用调用func (s *GenericServer) Call(ctx context.Context, req *GenericRequest) (*GenericResponse, error) {handler, ok : s.registry.Get(req.Service, req.Method)if !ok {return nil, status.Errorf(codes.NotFound, service %s.%s not found, req.Service, req.Method)}// 反序列化请求var payload interface{}if err : json.Unmarshal(req.Payload, payload); err ! nil {return nil, status.Errorf(codes.InvalidArgument, invalid payload: %v, err)}// 执行处理resp, err : handler(ctx, payload)if err ! nil {return GenericResponse{Code: 500,Message: err.Error(),}, nil}// 序列化响应data, err : json.Marshal(resp)if err ! nil {return nil, status.Errorf(codes.Internal, marshal error: %v, err)}return GenericResponse{Code: 200,Message: success,Data: data,}, nil}2. 高级基于反射的自动路由2.1 结构体服务自动注册package mainimport (contextencoding/jsonfmtreflectstringsunicodegoogle.golang.org/grpc/codesgoogle.golang.org/grpc/status)// AutoRegister 自动扫描结构体方法并注册func (r *ServiceRegistry) AutoRegister(serviceName string, serviceImpl interface{}) error {v : reflect.ValueOf(serviceImpl)t : v.Type()// 遍历所有方法for i : 0; i v.NumMethod(); i {method : t.Method(i)// 只导出公开方法if !isExported(method.Name) {continue}// 分析方法签名: func(ctx context.Context, req T) (resp T, error)if method.Type.NumIn() ! 2 || method.Type.NumOut() ! 2 {continue // 不符合标准handler签名}// 检查第一个参数是否为context.ContextctxType : method.Type.In(0)if ctxType ! reflect.TypeOf((*context.Context)(nil)).Elem() {continue}// 获取请求类型reqType : method.Type.In(1)respType : method.Type.Out(0)// 创建闭包处理函数handler : func(ctx context.Context, req interface{}) (interface{}, error) {// 将map[string]interface{}转换为具体类型reqBytes, _ : json.Marshal(req)reqPtr : reflect.New(reqType)if err : json.Unmarshal(reqBytes, reqPtr.Interface()); err ! nil {return nil, err}// 调用方法results : v.Method(i).Call([]reflect.Value{reflect.ValueOf(ctx),reqPtr.Elem(),})// 处理错误if !results[1].IsNil() {return nil, results[1].Interface().(error)}return results[0].Interface(), nil}r.Register(serviceName, method.Name, handler)}return nil}func isExported(name string) bool {if name {return false}r : []rune(name)[0]return unicode.IsUpper(r)}// 使用示例 // UserRequest 具体请求类型type UserRequest struct {ID int64 json:idName string json:name}// UserResponse 具体响应类型type UserResponse struct {ID int64 json:idName string json:nameEmail string json:email}// UserService 业务服务type UserService struct{}func (s *UserService) GetUser(ctx context.Context, req UserRequest) (*UserResponse, error) {// 业务逻辑return UserResponse{ID: req.ID,Name: req.Name,Email: userexample.com,}, nil}func (s *UserService) CreateUser(ctx context.Context, req UserRequest) (*UserResponse, error) {// 创建逻辑return UserResponse{ID: 100,Name: req.Name,Email: newexample.com,}, nil}// 初始化func main() {registry : NewServiceRegistry()// 自动注册所有方法userSvc : UserService{}if err : registry.AutoRegister(UserService, userSvc); err ! nil {panic(err)}// 启动gRPC服务器...}3. 流式通用接口3.1 双向流处理// StreamCall 实现双向流func (s *GenericServer) StreamCall(stream GenericAPI_StreamCallServer) error {ctx : stream.Context()// 为每个流创建会话状态session : StreamSession{ID: generateSessionID(),Streams: make(map[string]chan *GenericResponse),}// 处理流入消息errChan : make(chan error, 1)go func() {for {req, err : stream.Recv()if err ! nil {errChan - errreturn}// 异步处理每个请求go s.handleStreamRequest(ctx, session, req, stream)}}()// 等待流结束return -errChan}func (s *GenericServer) handleStreamRequest(ctx context.Context,session *StreamSession,req *GenericRequest,stream GenericAPI_StreamCallServer,) {handler, ok : s.registry.Get(req.Service, req.Method)if !ok {stream.Send(GenericResponse{Code: 404,Message: handler not found,})return}// 流式处理支持推送respChan : make(chan *GenericResponse, 10)session.Lock()session.Streams[req.Method] respChansession.Unlock()// 执行处理支持异步推送go func() {payload : make(map[string]interface{})json.Unmarshal(req.Payload, payload)resp, err : handler(ctx, payload)var respData []byteif err nil {respData, _ json.Marshal(resp)}stream.Send(GenericResponse{Code: func() int32 { if err ! nil { return 500 }; return 200 }(),Message: func() string { if err ! nil { return err.Error() }; return success }(),Data: respData,})}()}4. 客户端通用调用封装4.1 动态客户端package clientimport (contextencoding/jsonfmtgoogle.golang.org/grpcgoogle.golang.org/grpc/metadata)// GenericClient 通用gRPC客户端type GenericClient struct {conn *grpc.ClientConnclient GenericAPIClient}func NewGenericClient(target string, opts ...grpc.DialOption) (*GenericClient, error) {conn, err : grpc.NewClient(target, opts...)if err ! nil {return nil, err}return GenericClient{conn: conn,client: NewGenericAPIClient(conn),}, nil}// Call 通用调用方法func (c *GenericClient) Call(ctx context.Context,service, method string,req, resp interface{},opts ...grpc.CallOption,) error {// 序列化请求payload, err : json.Marshal(req)if err ! nil {return fmt.Errorf(marshal request: %w, err)}// 构建通用请求genericReq : GenericRequest{Service: service,Method: method,Payload: payload,}// 执行调用genericResp, err : c.client.Call(ctx, genericReq, opts...)if err ! nil {return err}if genericResp.Code ! 200 {return fmt.Errorf(business error: %s, genericResp.Message)}// 反序列化响应return json.Unmarshal(genericResp.Data, resp)}// CallWithMetadata 带元数据的调用func (c *GenericClient) CallWithMetadata(ctx context.Context,service, method string,req, resp interface{},md map[string]string,opts ...grpc.CallOption,) error {// 注入metadatactx metadata.NewOutgoingContext(ctx, metadata.New(md))return c.Call(ctx, service, method, req, resp, opts...)}// Close 关闭连接func (c *GenericClient) Close() error {return c.conn.Close()}4.2 使用示例func main() {client, err : NewGenericClient(localhost:50051, grpc.WithInsecure())if err ! nil {panic(err)}defer client.Close()// 调用UserService.GetUserreq : UserRequest{ID: 123}var resp UserResponseerr client.Call(context.Background(),UserService,GetUser,req,resp,)if err ! nil {panic(err)}fmt.Printf(User: %v\n, resp)}5. 完整架构图┌─────────────────────────────────────────────────────────────┐│ Client Side │├─────────────────────────────────────────────────────────────┤│ Service Stub (强类型) │ GenericClient (动态) ││ userSvc.GetUser(ctx, req) │ client.Call(ctx,User,Get,req,resp) │└──────────┬──────────────────┬───────────────────────────────┘│ │▼ ▼┌─────────────────────────────────────────────────────────────┐│ gRPC Transport ││ HTTP/2 Protobuf 序列化 │└──────────┬──────────────────┬─────────────────────────────┘│ │▼ ▼┌─────────────────────────────────────────────────────────────┐│ Server Side │├─────────────────────────────────────────────────────────────┤│ ┌─────────────────────────────────────────────────────────┐││ │ GenericServer (统一入口) │││ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │││ │ │ Call │ │ StreamCall │ │ HealthCheck │ │││ │ │ (Unary) │ │ (Bidi Stream)│ │ │ │││ │ └──────┬──────┘ └──────┬──────┘ └─────────────┘ │││ │ │ │ │││ │ ▼ ▼ │││ │ ┌─────────────────────────────────────────────────┐ │││ │ │ ServiceRegistry (路由表) │ │││ │ │ map[UserService.GetUser] → Handler │ │││ │ │ map[OrderService.Create] → Handler │ │││ │ └──────────────────┬────────────────────────────┘ │││ │ │ │││ │ ┌───────────┼───────────┐ │││ │ ▼ ▼ ▼ │││ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │││ │ │UserService│ │OrderService│ │PayService │ │││ │ │ (AutoReg) │ │ (AutoReg) │ │ (Manual) │ │││ │ └──────────┘ └──────────┘ └──────────┘ │││ └─────────────────────────────────────────────────────────┘│└─────────────────────────────────────────────────────────────┘6. 进阶插件化中间件// Middleware 通用中间件类型type Middleware func(ctx context.Context, req interface{}, info CallInfo, handler Handler) (interface{}, error)type CallInfo struct {Service stringMethod string}// Chain 中间件链func Chain(middlewares ...Middleware) Middleware {return func(ctx context.Context, req interface{}, info CallInfo, handler Handler) (interface{}, error) {// 构建调用链chain : handlerfor i : len(middlewares) - 1; i 0; i-- {m : middlewares[i]next : chainchain func(ctx context.Context, req interface{}) (interface{}, error) {return m(ctx, req, info, next)}}return chain(ctx, req)}}// 使用示例日志中间件func LoggingMiddleware(ctx context.Context, req interface{}, info CallInfo, handler Handler) (interface{}, error) {log.Printf([GRPC] %s.%s called, info.Service, info.Method)resp, err : handler(ctx, req)log.Printf([GRPC] %s.%s finished: err%v, info.Service, info.Method, err)return resp, err}这套设计提供了类型安全与动态灵活的平衡- 服务端支持自动注册反射和手动注册- 客户端支持强类型stub和动态调用- 扩展中间件链、流式处理、元数据传递
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2413860.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!