• 分享一种不太完美的接入网关设计
  • 来源:腾讯大讲堂

作者:朱江,腾讯工程师。
写在前面:限制基于C++ 98和taf框架实现。众所周知,C++98并没有像JAVA那样的反射机制,也不想引入第三方反射库(RTTR,cpgf...)。思路由于C++ 98没有反射机制,那么如何根据客户端传过来的命令字创建对象呢,如果是硬编码在代码里,那么可以这样写:switch (cmd)
{
case HEAD: new head;
case REQ: new req;
}很容易我们可以看出一个致命缺点,那就是新增或修改协议,代码也需要作相应的修改,这样费时费力,也容易出错。如何解决这个问题呢,可以利用C++静态类对象自动创建,从而自动执行构造函数的特性,把相关的类型信息注册到map结构里,这样就可以通过命令字得到对应的类对象,就像类工厂一样。但是这样还不够,因为当新增加一个协议结构体时,需要在ProxyServer代码里增加对应的类型注册代码,如:REGISTER_CLASS(THComm, JceStructBase, _Notification, AddNotiReq)。解决办法是利用JCE2CPP工具,当转换JCE文件为C++代码时,把相应的注册代码也添加到JCE产生的CPP文件中。通过命令字字符串得到类对象,就可以把请求消息里的JSON数据序列化为JCE对象结构,从而完成参数的JCE序列化,实现TAF接口+JCE调用。类对象注册及参数注册我们先来看一个客户端请求消息的例子,如下:{
"args": {
"req": {
"hospitalId": "10056"
},
"head": {
"requestId": "ooJQ346G2CMqcSujAt8yE8-Stutc",
"openId": "ooJQ346G2CMqcSujAt8yE8-Stutc"
}
},
"service": "TencentHealthRegister",
"func": "getHospitalInfo",
"context": {
"requestId": "b9bf3541-3753-11e9-8213-e5de4f5e7b53",
"traceId": "b9bf3540-3753-11e9-8213-e5de4f5e7b53"
}
}对应的JCE接口定义,如下:module TencentHealthMini {
struct ThHead{
0 optional string requestId;
1 require string openId;
2 optional string channel;
3 optional string cityCode;
};
struct HospitalReq{
0 require string hospitalId;
1 optional string platformId;
};
struct HospitalRsp{
0 require Result result;
1 require HospitalInfo hospitalInfo;
};
interface ThRegisterMain {
int getHospitalInfo(ThHead head,HospitalReq req, out HospitalRsp rsp);
}
}我们可以看到,请求消息里,客户端会在请求消息里告诉ProxyServer,请求的服务是"service": "TencentHealthRegister",调用的接口是"func": "getHospitalInfo",而接口参数通过”req”和”head”的json串和JCE接口定义的req和head结构对应。这里就有一个问题需要我们解决,如何知道req对应的类型呢?一种方法是通过配置,在我们的服务配置文件上写明某服务某接口的req对应类型是HospitalReq,如下所示,这样做的缺点是协议改动,配置也需要跟着改动。

head = ThHead
req = HospitalReq

rsp = HospitalRsp
</getHospitalInfo>较好的办法是:可以像类对象注册一样,把参数类型也注册到map,同时TAF接口参数JCE序列化是需要按顺序的,所以参数顺序也是需要我们知道的。1.类对象注册实现定义一个静态map

<< 41 42 43 44 45 >>