概述
在Request-Response模式下,网关需要将后端模块返回的数据在返回给客户端即Response,此时需要网关与客户端约定一套数据结构,方便客户端解析
客户端与网关是长连接,因此不同的mqtt包会交叉传递
示例时序图
sequenceDiagram
participant 客户端
participant 网关
participant 后端模块
客户端 ->> 网关:Request01(topic=HelloWord/HD_Say/001)
网关 ->> 后端模块:RPC01
客户端 ->> 网关:Request02(topic=HelloWord/HD_Login/002)
网关 ->> 后端模块:RPC02
后端模块 -->> 网关:RPC01
网关 -->> 客户端:Response01(topic=HelloWord/HD_Say/001)
客户端 ->> 网关:Request03(topic=HelloWord/HD_Say/003)
网关 ->> 后端模块:RPC03
后端模块 -->> 网关:RPC03
网关 -->> 客户端:Response03(topic=HelloWord/HD_Say/003)
后端模块 -->> 网关:RPC02
网关 -->> 客户端:Response02(topic=HelloWord/HD_Login/002)
主题(topic)
Response时,网关发送给客户端的topic跟Request时完全一致,因此客户端可通过唯一topic确定返回数据是哪个请求的。
消息体(body)
mqant默认封装规则
mqant默认封装为json结构体,具体结构如下
{
Error string
Result interface{}
}
Result
代表hander函数执行正确时返回的结果
类型
- bool
- int32
- int64
- long64
- float32
- float64
- []byte
- string
- map[string]interface{}
Error
代表hander函数执行错误时返回的错误描述
类型
- string
- error
自定义返回格式
mqant默认规则使用json来封装,但实际情况下不同的应用场景可能需要的封装数据格式有所不同,例如有些场景倾向于用protobuf封装。 且默认的封装规则不支持自定义数据类型。
app.SetProtocolMarshal(func(Result interface{},Error string)(module.ProtocolMarshal,string){
//下面可以实现你自己的封装规则(数据结构)
r := &resultInfo{
Error: Error,
Result: Result,
}
b,err:= json.Marshal(r)
if err == nil {
//解析得到[]byte后用NewProtocolMarshal封装为module.ProtocolMarshal
return app.NewProtocolMarshal(b),""
} else {
return nil,err.Error()
}
})
ProtocolMarshal
如下 mqant默认返回值是这样的 result map[string][string], err string
func (m *Login) login(session gate.Session, msg map[string]interface{}) (result map[string][string], err string) {
。。。
return map[string][string]{
"info":"login success"
}, ""
}
rpc通信编码/解密流程: map—>[]byte ——— []byte—>map—>[]byte—> client
最终发送给客户端的是[]byte类型,中间经历一次 []byte—>map—>[]byte 的无用编解码流程
如何省掉无效的编解码流程呢?
答案: 在后端模块提前编码为[]byte类型,如何实现见以下代码:
func (this *Login) login(session gate.Session, msg map[string]interface{}) (result module.ProtocolMarshal, err string) {
return this.App.ProtocolMarshal("","login success","")
}
实现原理:
返回值用 this.App.ProtocolMarshal 函数封装一遍即可,返回值改为了module.ProtocolMarshal类型