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

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

很多请求的场景,返回的条数是动态变化的,比如订单数量。用户每下一个订单,那么请求返回的数量就会加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

时间: 2024-11-08 11:57:51

结构体作为接口的注意事项的相关文章

换个语言学一下 Golang (9)——结构体和接口

基本上到这里的时候,就是上了一个台阶了.Go的精华特点即将展开. 结构体定义 上面我们说过Go的指针和C的不同,结构体也是一样的.Go是一门删繁就简的语言,一切令人困惑的特性都必须去掉. 简单来讲,Go提供的结构体就是把使用各种数据类型定义的不同变量组合起来的高级数据类型.闲话不多说,看例子: type Rect struct { width float64 length float64 } 上面我们定义了一个矩形结构体,首先是关键是type表示要定义一个新的数据类型了,然后是新的数据类型名称R

C#学习记录4——结构体,接口

1.结构体 对于C++语言来说,其实结构体和类几乎没有什么太大的区别.类能够实现的功能,使用结构体大部分也可以. 不过,在C#里面,我们把结构体看作是一种轻量的类的替代品.它和类一样有构造方法,属性,成员属性/数据,甚至是操作符.注意struct构造方法必须有传入参数. 当然struct也不是完全支持类的所有功能的. 首先,结构体无法进行继承.也就是说,结构体不想类那样灵活,代码也无法复用. 其次,也是非常重要的一点:结构体是一种值类型,而类是引用类型.这两种类型的区别,可以查看C#学习记录3上

c#学习笔记之结构体和接口

一.结构体 个人认为结构体就是一种简化的类,类和结构体的功能基本上差不多.但是,结构体与类在语法以及使用上也有一定的区别. 1.结构体是值类型(value types),而类是引用类型(reference types) 2.不像类一样,结构体可以不使用new来实例化一个对象. 3.结构体能声明构造函数,但是必须传入参数. 4.结构体不能从另一个结构体或类继承. 结构体的声明: public struct man { methods; } 二.接口(interface) C#中只允许单继承,也就是

八、结构体和接口

结构体定义: 和C++ 一样,Golang的结构体也是封装数据.可以说是面向对象吧. 结构体的组合函数: package main import ( "fmt" ) type Node struct { x, y int } // 结构体外接函数(能不能在结构体内写,目前还不清楚能不能在内部定义 func (node Node) area() (res int) { res = 0 res = node.x * node.y return } func main() { var nod

黑马程序员——c语言中结构体的使用以及注意事项和实际应用

1.结构体和数组的区别①结构体:结构体可以由多个不同类型的数据构成,可以 包含int double等多种类型②数组:数组则只能由多个相同类型数据构成 2.结构体的定义①先定义结构体类型 struct Person { int age; //age height name 三个变量可以称之为结构体成员或者属性 double height; char*name; } ②根据结构体类型定义结构体变量 struct Person p={20,1.75,"tom"}; p.age=30; p.n

黑马程序员-----结构体数组

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ----- 第一讲  结构体数组 一.结构体数组的概念       数组的元素也可以是结构类型的.因此可以构成结构型数组.结构数组的每一个元素都是具有相同结构类型的下表结构变量.在实际应用中,经常用结构数组来表示具有相同数据结构的一个群体.如一个班的学生

面向对象基础——结构体

1.结构体的语法 定义的时候需要使用关键字struct [public] struct 结构名 { public 类型名 变量名; … } 我们常见的结构体:System.Drawing.Point.Size.Color 注意: 1.结构使用时可以new,也可以不new.如果不new,则使用前必须为结构成员赋值. 2.在结构中不能为变量直接赋初值,除非const(常量).static(静态变量) 2.结构体与类 它们是 .NET Framework 中的通用类型系统的两种基本构造.两者在本质上都

C#学习笔记之结构体

1.概述 结构是一种与类相似的数据类型,不过它较类更为轻量,一般适用于表示类似Point.Rectangle.Color的对象.基本上结构能办到的类全都能办到,但在某些情况下使用结构更为合适,后面会有提到. 结构具有以下特点: 结构可以实现接口. 结构可以声明带参数的构造函数. 结构不能声明默认构造函数(没有参数的构造函数)或析构函数. 结构是值类型,而类是引用类型. 实例化结构体时可以不使用new运算符. 结构类型是不可抽象.隐式密封的,故不能使用abstract和sealed修饰符. 在结构

浅析C#中的结构体和类

类和结构是 .NET Framework 中的常规类型系统的两种基本构造. 两者在本质上都属于数据结构.封装着一组总体作为一个逻辑单位的数据和行为. 数据和行为是该类或结构的"成员",它们包括各自的方法.属性和事件等 对于C/C++程序员来说.结构体和类的差别非常小.仅仅是结构体的默认成员变量为public,类的默认成员变量为private. 可是对于C#来说,结构体和类有非常多的不同. 首先来谈一谈为何须要结构体: 最主要的原因就是结构体有能力去管理.使用不同数据类型的组合. .NE