结构体作为接口的注意事项

it2026-01-12  3

在后端向前端回复数据时,需要将结构化数据通过网络传输给前端,而网络传输是字节流传输,前端收到的是一段数据,那么,问题就落脚在如何解析这段数据。

很多请求的场景,返回的条数是动态变化的,比如订单数量。用户每下一个订单,那么请求返回的数量就会加1.这时候,如何较好的返回动态数据呢?这个看使用怎样的存储格式来承载可变长度的数据返回。就目前已知的处理方法:

使用 json 格式使用 protobuf 格式使用 struct 格式

由于工作需要,这里使用 struct 格式来进行数据的包裹。

固定长度的返回数据

比如,查询某个用户的账户余额,返回的结构体类似如下:

struct TAccountCapital : struct PacketHead { double m_dCapital; }

struct PacketHead为包头结构体,里面的内容为传输过程中的一些通用选项,在此不表。

当该结构体后续有扩展时,只要保证后续新增的字段始终放在后面,那就可以保持升级后新旧版本的兼容性。

可变长度的返回数据

比如,查询某个用户的当日订单信息,返回的结构体类似如下:

struct TAccountOrder :struct PacketHead { int m_nCount; // 订单个数 TOrderInfo m_OrderInfo[1]; // 订单数据 } struct TOrderInfo { int m_nOrderNo; // 订单编号 string m_nOrderProductName; // 订单商品名称 }

这里用到的 linux下的 零长数组技巧,此处不再赘述。

客户端在接收到此类数据时,先通过 sizeof(TOrderInfo) * m_nCount得到订单数据的真实长度,然后以sizeof(TOrderInfo)为步长,将内存中数据整理输出,显示出来。

到这一步,看起来都很美好。

再往下看,随着业务的发展,订单信息需要新增一个字段,比如新增订单折扣信息。此时的返回结构体如下:

struct TOrderInfo { int m_nOrderNo; // 订单编号 string m_nOrderProductName; // 订单商品名称 double m_dOrderDiscount; // 订单折扣信息 }

一旦结构体有所改变,就存在前后端面对的结构体不一致,如果前端还按照原有的步长来截取内存输出,随后的订单信息就会全部错乱。

造成这个问题的原因是前端使用的结构体与后台的不一致,后台的修改带来了兼容性问题。既然问题根源知道了,那么解决的方法也有浮出水面了。那就是让前端知道真正的步长,这个步长不能依赖于前端能够看到的结构体长度,而要通过其他途径了解真实的长度,而这个真实的长度,只有后台了解,因此,需要后台增加一个字段,表示传递结构体真正的长度。

struct TAccountOrder :struct PacketHead { int m_nCount; // 订单个数 int m_nItemSize; // 订单数据结构体大小 TOrderInfo m_OrderInfo[1]; // 订单数据 }

结论

在使用结构体传递可变数据时,使用零长数组传输数据时,需要增加返回的结构体大小成员。

同时,要同前端开发人员做好约定,在解析数据时,要依赖接口中的结构体大小成员,而不要依赖自己算出来的结构体成员大小。

转载于:https://www.cnblogs.com/cherishui/p/10340845.html

最新回复(0)