动态路由 WebSocket 消息到 gRPC 服务 - 【Invoke】
有时候,我们需要将通过 WebSocket 收到的消息动态路由到不同的 gRPC 服务。需要支持动态删减服务,动态删减rpc方法。
这篇博客将介绍如何使用 Go 实现这一功能。我们将重点解析 CallInvoke
方法,该方法接受一个消息类型和数据,然后将其转发到相应的 gRPC 服务并返回结果。
代码解析
以下是 CallInvoke
方法的实现:
func CallInvoke(ttype string, datas []byte) ([]byte, string, error) {
var err error
array := strings.Split(ttype, ".")
servername := array[0]
method := array[1]
rpcConn := getRpcConnect(servername)
if st != nil {
req := &Common.Empty{}
ack := &Common.Empty{}
if err = proto.Unmarshal(datas, req); err != nil {
goto endFunc
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second30)
defer cancel()
funcName := strings.Replace(method, "Req", "", -1)
fullPath := fmt.Sprintf("/%s.%sService/%s", servername, servername, funcName)
log.Printf("invoke req : %s", fullPath)
err = rpcConn.Invoke(ctx, fullPath, req, ack)
if err != nil {
goto endFunc
}
data, err := proto.Marshal(ack)
if err != nil {
goto endFunc
}
log.Printf("invoke ack : success", ack)
return data, servername + "." + funcName + "Ack", nil
}
endFunc:
if err != nil {
log.Printf("invoke ttype:%s err:", ttype, err.Error())
return []byte(servername), "", err
}
return nil, "", nil
}
主要步骤解析
-
解析消息类型
array := strings.Split(ttype, ".") servername := array[0] method := array[1]
将通过 WebSocket 收到的消息类型(例如 “Service.MethodReq”)分解为服务名和方法名。
-
建立 gRPC 连接
rpcConn := getRpcConnect(service)
调用
getRpcConnect
函数获取gRPC 连接。 -
初始化请求和响应对象
req := &Common.Empty{} ack := &Common.Empty{} if err = proto.Unmarshal(datas, req); err != nil { goto endFunc }
Common.Empty为空proto结构体,将通过 WebSocket 接收到的数据反序列化为请求对象
req
。如果反序列化失败,跳转到endFunc
标签。 -
设置上下文和超时
ctx, cancel := context.WithTimeout(context.Background(), time.Second30) defer cancel()
创建一个上下文,并设置一个 30 秒的超时时间。
-
构造 gRPC 方法全路径并调用
funcName := strings.Replace(method, "Req", "", -1) fullPath := fmt.Sprintf("/%s.%sService/%s", servername, servername, funcName) log.Printf("invoke req : %s", fullPath) err = rpcConn.Invoke(ctx, fullPath, req, ack) if err != nil { goto endFunc }
构造 gRPC 方法的全路径(例如
/Service.ServiceService/Method
),并通过Invoke
方法调用该 gRPC 服务。如果调用失败,跳转到endFunc
标签。 -
处理响应
data, err := proto.Marshal(ack) if err != nil { goto endFunc } log.Printf("invoke ack : success", ack) return data, servername + "." + funcName + "Ack", nil
将响应对象
ack
序列化为字节数组,并返回给调用者。如果序列化失败,跳转到endFunc
标签。 -
错误处理
endFunc: if err != nil { log.Printf("invoke ttype:%s err:", ttype, err.Error()) return []byte(servername), "-1", err } return nil, "", nil
在错误处理部分,记录错误日志并返回错误信息。
总结
通过这段代码,我们展示了如何将 WebSocket 消息动态路由到 gRPC 服务。该方法不仅处理了请求的反序列化和响应的序列化,还包括了上下文管理和超时设置。这样,你就可以在后端灵活地处理来自不同客户端的请求,并将它们路由到合适的 gRPC 服务进行处理。
希望这篇博客能帮助你理解如何实现消息的动态路由!如果你有任何疑问,请随时留言。