V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
darknoll
V2EX  ›  程序员

后端传过来的某些属性不固定,有时候有,有时候没有,这样合理吗?

  •  5
     
  •   darknoll · 32 天前 · 11744 次点击
    这是一个创建于 32 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如和后端商定好了,返回的接口格式是: { "A": "", "B": [{}, {}] } 这时候后端说了,B 的数据有时候没有,如果没有的话就直接返回{A:""} 我让他返回{"A":"***", "B":[]}

    哪种方案好?

    187 条回复    2021-01-28 16:43:25 +08:00
    1  2  
    yaphets666
        101
    yaphets666   31 天前
    其实这是无可争议的.你想就知道了.关系型数据库里头,一个字段没值,是空呢,还是这条数据没这个字段?
    bakujin
        102
    bakujin   31 天前
    其实我们这么做是为了节约带宽资源
    Twain
        103
    Twain   31 天前
    应该先思考应不应该返回,而不是你觉得好不好处理,这个东西本来就没有,为什么还要给你字段呢?先问该不该
    zhuweiyou
        104
    zhuweiyou   31 天前
    B 没有 不返回, 对我来说 更好判断.
    如果返回个 [], null, {} 或者 其它值, 我还有心智负担, 它到底空的时候是啥.
    anson2017
        105
    anson2017   31 天前
    我觉得都一样,无非是判断 undefined 还是判断空数组的问题
    Zoomz
        106
    Zoomz   31 天前
    后端是用 Java 写的吗,如果是用 DTO 返回的话理论就是第二种(但是 B 返回的为 null ),除非它使用 Map 装的。。
    shew5689
        107
    shew5689   31 天前
    if("key" in data){} 判断不就 ok 了吗~ 反正合不合理,总有人妥协,不是服务端处理,就是前段处理~
    trlove
        108
    trlove   31 天前
    @Zoomz 你忘了可以配置 key 对应的值如果为 null,连 key 都不返回的吗……并不是非得是 map 装
    justsosososo
        109
    justsosososo   31 天前
    没什么合理不合 你不干就后端干 你两都不想干就招个中台来干
    zhangshine
        110
    zhangshine   31 天前
    防御性编程,即使后端返回第二种 ,前端也应该判断会不会出现第一种情况
    bfdh
        111
    bfdh   31 天前
    @anjianshi 前端代码复杂起来不好保证所有处理这个字段的地方都妥善处理了空值,而后端只要在返回的地方处理一次就好了。

    换成下面这种说法是不是也没错?

    后端代码复杂起来不好保证所有处理这个字段的地方都妥善处理了空值,而前端只要在接收的地方处理一次就好了。
    pangleon
        112
    pangleon   31 天前
    这种情况我见过,
    公司部分项目约定后端字段为 null 不返回
    实际需要看你们的约定,没什么合理不合理,看约定和场景而已
    别这么死脑筋,你觉得用不到可能人家一个接口对接好几个前端,别人需要
    yogogo
        113
    yogogo   31 天前
    前端应该也要所有情况都要考虑到,这样就不用怕后端返回什么类型了
    zishaofei221
        114
    zishaofei221   31 天前
    约定好就行了。你不同意,就找他老板商量。
    不返回可能是偷懒没 Vo,直接 map 了个数据给你。
    no1xsyzy
        115
    no1xsyzy   31 天前
    应符合语义。
    这样说有点不明不白,还是解释一下:
    打个比方,API 请求物品栏内容。那么,一个有物品栏但物品栏为空的角色,和一个没有物品栏的角色,分别是 [] 和 null
    但 null 和不存在此 key 应当是同义的(根据 JSON merge patch RFC )。
    说不定还是要推荐一下 GraphQL 之类请求方指定 spec 的方案(中台……
    caijihui11
        116
    caijihui11   31 天前
    这个取决于前端同学的看法,遇到迷惑可以问一下后端同学具体判断逻辑,接口文档只会提供一份最全的接口返回,后端大部分不返回的一些字段是用不到的,能用到的也是有前置条件。
    前置条件可能是:
    1 某个字段 是否 undefined
    2 固定返回某个值的状态
    Yano
        117
    Yano   31 天前
    后端序列化 json 的时候,可以指定空或 null 值直接不返回的。
    即使后端返回了,你也应该防御编程,判断一下吧。我写接口,前端所有的参数都不信任的,都要校验合法性……
    kangyan
        118
    kangyan   31 天前
    @bfdh 或许需要一个中台?
    yaphets666
        119
    yaphets666   31 天前
    @justsosososo 当然不是了...合理就是合理 不合理就是不合理 一个字段没有值的时候如何处理,参考关系型数据库...
    cmostuor
        120
    cmostuor   31 天前
    估计没有统一的规范约束着
    guyeu
        121
    guyeu   31 天前
    这种难道不是前后端商议通信协议,共同定义协议( protobuf 、json scheme 、dsl ),分别生成基于前后端技术栈的通信层数据结构和基本逻辑,然后基于生成的代码编写具体的业务逻辑,这个时候可能是空就判空,不可能是空就不判空?
    trlove
        122
    trlove   31 天前
    @laminux29 1.不敢苟同您的加强鲁棒性设计。100 个字段出现 100 个状态字段再去分别表示状态,在我看来就是过度设计,滥用设计模式。完全是为了套设计模式而设计,增加了操作流程,延长了操作线。
    2.不加状态字段,判断数据本身,如果发生错误,无非就是后端返回了前端没判断,后端没返回(如果前端判断了字段,即使后端出错,前端也不可能出错),那问题就回到了前端的判断问题。所以只需要前端看下代码有无判断就能立马知道是不是后端的错。再退一万步,您认为加了判断状态字段,排查快,不费时费力。但是您忽略了后端操作的错误性。如果上百个字段,您就能保证后端不犯错误忘记改某个字段状态?出现了问题,您能百分百确定是前端没判断 ,还是后端数据改变的不全?不还是得一个个去排查。而且还得是对着数据一个个看,看看哪个数据状态维护错了。您的加强鲁棒性吧问题前置到数据的初始化状态了,排查起来只会更复杂。本身并没有解决您说的犯错误问题。再退十万步,一个系统要想健壮就完全靠拼凑设计模式?就难道没有自测,测试专测,上线前回测,以及灰度?您所说的犯错误的情况在这些测试阶段就能被发现,解决您问题的是测试的流程而不是您的设计模式解决了犯错误的本质。
    3.个人理解任何设计模式的流行必然有其合理性。但我认为合理的利用设计模式可以锦上添花,不合理的套用设计模式只会是增加复杂度,并不能实质性解决问题。
    lonelymarried
        123
    lonelymarried   31 天前
    这真那后端没办法,一般如果我的项目,前后端都是我写,就自由多了。这不,后端又出问题了,app 都上线好久了,中途加了个需求,后端就出问题了,昨天反映了,今天还没答复。我是写过 java 后端的,知道这东西也就分分钟的事。没办法,公司的后端就这么搞。自己前后端都学学吧。
    GoNtte
        124
    GoNtte   31 天前
    第二种好 看返回就知道是数据结构了
    0x666666
        125
    0x666666   31 天前
    阿里云官网的做法是:如果 key 的 value 是 null,就不会返回 key 。
    第一:不会返回无意义的数据。
    第二:省流量(虽然省不了多少)。
    第三:如果要后端强制 key 的 value 是 null,要返回一个 key: "" 或 key:[],对于后端来说需要对每个属性都要进行初始化赋空值不说,还要在参数映射完以后,再做一次 null 检查,把 value 是 null 的 key 设空值。这个过程是一个比较麻烦并且没有必要的流程,而且还浪费服务器性能。
    第四:和楼上的老哥说的一样,前端不能把命运完全交给后端,自己也要做好空值判断,key 没有的情况。
    综上所述,我觉得前端做好对应的判断即可,没必要后端去做这些操作。
    0x666666
        126
    0x666666   31 天前
    @Zoomz #106 有的时候不是后端的锅,序列化框架会自动把 value 为 null 的 key 设为空。
    Sapp
        127
    Sapp   31 天前
    单个不存在的时候返回 null 、
    数组不存在返回空数组

    或者你干脆用 typescript,让后端搞个 OpenAPI,写个 node 读取 json 数据自动生成前端接口函数,顺带写上 interface,不就没这个问题了,返回的啥都无所谓,只要他定义好了你这边就有提示
    kifile
        128
    kifile   31 天前
    我会选择第二种,原因是 null 也是一种特殊情况啊,null 和 [] 其实是不等价的,如果业务逻辑中的确是空数组,那返回空数组无可厚非,而如果业务逻辑中应该是 null ,并且使用一些 json 库序列化 null 值,库会帮你删除掉 null 的 key
    notejava
        129
    notejava   31 天前
    前端喜欢第二种,后端喜欢第一种,大家都不想多写几层判断代码
    sevenzhou1218
        130
    sevenzhou1218   31 天前
    关系好,都不是事,关系不好,死怼。
    killerv
        131
    killerv   31 天前   ❤️ 5
    我很惊讶那么多说第一种的,B 是个 list,B 的数据没有也只代表 list 为空,不应该没有 B 这个属性,这是两个概念。
    举个例子:接口返回的数据表示某个人的一些信息,有个字段是 friends,类型是 list,他可以没有一个 friends,可以是空数组,但是作为人他一定具备 friends 这个属性。
    kltt22
        132
    kltt22   31 天前
    你给我个最全的字段,就啥事没有,就怕你现在返回的没有,一会又有了。上次对了个 java,本来说好了是最全的,后来实体类报错了,发现默默的多了几个字段。这玩意后端自己都控制不住的话,还是所有字段都返回吧。
    bootvue
        133
    bootvue   31 天前
    凡是为空的 最好都不返回那个字段

    按照某些前端的逻辑 B 是集合 返回个空集合 [] , 那 B 要是个 object 返回啥 : null 还是 {} , B 要是 number 返回啥: null 还是 0 完全都是扯淡

    不返回意义更明确 前端更好判断 typescript 约束更有意义
    asAnotherJack
        134
    asAnotherJack   31 天前
    @kltt22 #132 这种应该放在接口文档里
    andyli9449
        135
    andyli9449   31 天前
    把问题简化一下,比如一个用户属性。 有 email 字段,且并没有被设置。那么返回的格式应该是 { "email": null } .还是 { "email": ""}; 。API 文档中返回值的定义这个值应该是 string, 但返回 null 就和文档不符。但没有设置,email 值就是""也挺奇怪。比如年龄未设置 该返回时 {"age":null} 还是 {"age": 0} ,API 文档 age 字段肯定应该是数值(Int/Number) 。
    est
        136
    est   31 天前
    如果没有的话应该返回: {"A": "", "B": "null"}
    cyrbuzz
        137
    cyrbuzz   31 天前
    这个...我怎么觉得返回`{A:""}`其实也不省流量,如果这个接口在一次普通用户访问中只会调用固定的几次,这样前端本来可以写成`response.B[0]`的代码现在要写成`response.B && response.B[0]`,这样不仅没有省流量,还有可能会阻塞首屏加载的嘞= =...
    jrtzxh020
        138
    jrtzxh020   31 天前
    @whileFalse 一个?那是一百几十个属性,每个接口都要都不同。String 返回 null Array 也返回 null,前端没有强类型,但是前端变量也有数据类型的好吗
    bbao
        139
    bbao   31 天前
    基本原则:后端的做法好,没有就不传,节省网络传输流量贷款的浪费。

    可能一个请求会很大,这样做好处多,前端做校验处理啊;

    client -> server 后端在 rpc 到其他服务拿回来的数据,有变化肯定后端已经做好了处理。

    前端也要相应的咯。
    andyli9449
        140
    andyli9449   31 天前
    @killerv friends 没设置返回[]可以,我想知道如果年龄(age)这个属性没有设置应该返回什么 0 或者是 null 吗?
    midtin
        141
    midtin   31 天前
    服务器计算资源和带宽流量永远是最昂贵的资源,在合理的情况下减少后端的判断处理,通过输出更少的数据来节约流量,我认为是没问题的
    lhx6538665
        142
    lhx6538665   31 天前
    无所谓,怎样都行,这个问题你也可以问下自己,后端需要你传这种数据,你要怎么传
    killerv
        143
    killerv   31 天前
    @andyli9449 如果是我的话,我会用 null 。
    wangkun025
        144
    wangkun025   31 天前
    前端是需求方,前端说啥就是啥。
    这事后端没发言权。
    back0893
        145
    back0893   31 天前
    protobuff?
    导致的没有缺失?
    killerv
        146
    killerv   31 天前   ❤️ 2
    扯到带宽和流量就有点牵强了吧,{"B": []} 和 {} 能差多少流量?网络发展到这个时代,这个成本基本上可以忽略不计。规范是很重要的,语意不明的表达会增加很多沟通和开发成本。
    lychs1998
        147
    lychs1998   31 天前
    像 SpringBoot 的话,很可能是直接配置了 Jackjson 不输出 null 值。先和他确认一下是不是写公司后端基础框架的人规定的。如果需要完整的数据项,可以考虑直接和对方沟通。

    我觉得比较大的可能性是为了少写面向前端返回结果的 ViewModel,直接用字段最全的类,从数据库里直接查需要的字段填充,数据库里为 null 的值可能填充了一个 null,所以这个字段被当作是无效字段直接被 json 序列化工具砍掉了。
    cumt21g
        148
    cumt21g   31 天前
    应该保持字段的固定
    jhdxr
        149
    jhdxr   31 天前
    v2ex 的水平下降的有点严重啊。。。无脑站第二种的居然这么多?


    @killerv 你都能想到语义了,有没有想到不存在 b,或者 b 为 null,与 b 的值为[]这两者的语义是不同的?

    而且无论后端最终写成啥样,前端那边难道不应该始终检查一遍吗?
    gggxxxx
        150
    gggxxxx   31 天前
    都什么年代了,还提省流量和服务器开销......
    新观念,第二种方法保持字段的固定有很多优势,所付出的成本(开发精力和硬件资源)微不足道。
    坚持第一种方法太古典了,其实并没有省事。出了问题后端还不是要一起排查。
    jhdxr
        151
    jhdxr   31 天前
    @wangkun025 你可能对需求方这三个字有啥误解
    jason19659
        152
    jason19659   31 天前
    第一种,可选字段不判空是逻辑错误
    vincentxue
        153
    vincentxue   31 天前
    我全端通吃, 我的规则就是:
    1. 我支持你的想法。我的做法是这样,如果 B 是一个 Object,那么为空的时候返回 null,如果是一个 Array,为空的时候返回 []。
    2. 所有的字段都会存在,不允许有时候有 B 有时候没 B 的情况出现。

    这种情况下,Web 、iOS 、Android 都不会出问题,特别是 Android,Android 用 Gson 如果不做额外的工作,只要一个字段没有就会抛异常。

    我个人认为服务端某种意义上就是为客户端提供服务的,我写接口的时候一直都是本着方便别人麻烦自己的心态。如果双方出冲突,后端应该让步给前端。我最烦那种偷懒的人,明明知道那样做比较好,但是麻烦点,就各种推脱不做。
    killerv
        154
    killerv   31 天前
    @jhdxr 同一种类型,不应当存在某个特殊对象不存在 b 的可能性。Json 这种系统间交互的数据格式,不应该存在相同类型但是数据类型不统一的情况。你说的前端始终检查一遍就是额外的成本,如果都按照规范来,就不存在这个问题。
    killerv
        155
    killerv   31 天前   ❤️ 1
    @jhdxr 你这种用冗余代码兼容各种异常情况,看似健壮,实际上是对规范的破坏,带来的是沟通、维护成本的巨大提升。如果前后端都按照规范来,前端根本没必要校验这种情况。
    baixixi
        156
    baixixi   31 天前
    就这么点事,前后端都是一个 if else 的事,有那么难吗
    codingguy
        157
    codingguy   31 天前
    不返回 B 也没问题呀。前端直接 const list = response.B ?? [ ] 就好了
    oddisland
        158
    oddisland   31 天前
    res?.B ?? [ ]
    leeyom
        159
    leeyom   31 天前
    通常是第二种,第二种数据结构具有完整性,其实这种不管是前后端,如果做的严谨一点的话,前后端都要做判空处理
    wh1012023498
        160
    wh1012023498   31 天前
    又到了前后端为了方便不方便争论了,前端方便后端就不方便了,后端方便前端就不方便了。
    所以这不是技术问题,这是话语权之争。
    q1angch0u
        161
    q1angch0u   31 天前
    月经贴……
    dm4927
        162
    dm4927   31 天前
    啊,这问题我熟,之前驻场一家公司就是这样的。
    后端接口只返回存在值的字段,然后出现了以下问题,之后改成了所有值都传。
    第一是,有些接口返回的是 Object 套 Object 的,大概三四层,这就导致了,前端需要一层层的处理。
    第二是,因为项目比较大,陆陆续续来了很多人,然后每来一个人,都要和他沟通说明下为什么有的时候有这个字段,有的时候没有,而由于业务原因,好多时候还需要讲一下触发这个字段的方式,沟通成本直线飙升。
    salmon5
        163
    salmon5   31 天前
    说省流量的,不应该带个狗头吗
    Hoshinokozo
        164
    Hoshinokozo   31 天前
    作为前端,肯定是倾向第二种的,保证数据的一致性能减少大量的的沟通成本和 bug 几率,但是看站内后端老哥的回答第一种在某些特殊情况下也是有一定的道理的,所以说到底这事还是在于沟通,前后端提前商量好,到时候出问题分锅也有依据。
    SyncWorld
        165
    SyncWorld   31 天前
    一开始返回的时候用直接扔到 map 里返回,过滤了 null 的 key,直到有一天,连接 ORacle 发现直接扔到 Map 里返回到前端的字段全 TMD 是大写,我的强迫症迫使我又封装成对象返回,这件事充分说明怎么返回都无所谓,关键还是协商问题
    alreadytaken
        166
    alreadytaken   31 天前
    最佳解决方案是有的。
    背景:最近在捣鼓 vue3+ts 写新项目。
    使用 openapi-typescript 连后端给的 swagger,前后端 require,response 定义完全一致,完美解决。
    THESDZ
        167
    THESDZ   31 天前
    我建议返回

    {"A":"val","B":null}

    因为 null 和[]完全是两码事,根据后端说的话: B 的数据有时候没有 即 B 此时应该为 null

    而关于属性不固定等,应该看文档

    实际上仍然是协商的问题
    xaplux
        168
    xaplux   31 天前
    后端返回的 json 格式估计设置了忽略值为 null 的字段,前后端约定好就行了
    qdpoboy
        169
    qdpoboy   31 天前
    倾向于第二种。

    那假如这是一个开放给外部的 api 接口,那会是那种好呢?如果是字段有值才返回,那文档上每个字段是不是都要写上一句,如果有值则该字段返回,否则不返回
    xumng123
        170
    xumng123   31 天前 via iPhone
    restful 的接口定义有 option,前端就要按照两种情况处理,大家可以看大厂的接口,他们不会给你 option 返回[]的。
    wangkun025
        171
    wangkun025   31 天前
    @jhdxr 没啥误解。
    我是做后端开发的。前端不发 request,我服务器都不开机。
    DogMingDD
        172
    DogMingDD   31 天前
    这个就是事情谁来做的问题,没有合不合理的问题。
    exonuclease
        173
    exonuclease   31 天前
    理论上不是应该实例化一个 entity object 怎么能写出来这种代码的
    calmlyman
        174
    calmlyman   31 天前
    各位大佬们写的都是重量级 nb 项目吧?才需要这么省流量吧
    jhdxr
        175
    jhdxr   31 天前
    @wangkun025 厉害厉害,你服务器不开机是谁在那监听前端的请求的?莫非人肉 oncall ?一个请求过来你再开机?
    saberlong
        176
    saberlong   31 天前 via Android
    刚好手头就遇到一个场景。大致是中间层汇聚各种内容一起返回。但是只知道 key,以及值是一个 json 。某项 key 内容不存在时,你让中间层实例化也很为难啊,都不知道内容。
    Rhonin
        177
    Rhonin   31 天前
    @trlove 大厂的屎山都是香的呗?`有时候可能是单条数据 有时候可能是单字符 有时候可能是数组,`合着您觉着这是合理的,不用辩了
    wangkun025
        178
    wangkun025   31 天前
    @jhdxr 阅读能力有待提高。
    trlove
        179
    trlove   31 天前
    @Rhonin 不好意思,你可能不知道什么是全局设计。也不懂啥叫泛型,不知道啥叫兼容。你直接说你懒得在前端做判断不就得了,还觉得不合理。不合理您倒是给出您的见解,并解决问题。而不是一句暴躁的不用辩了。您这么高贵,都不辩,那您在在个这个主题下发什么言,原来 v2 的某些前端就这个水平。另外你不认可的设计就说人大厂的就是屎山,我只能说您水平实在是高。拜拜了您嘞
    jimrok
        180
    jimrok   31 天前
    对于集合,接口永远不要返回 null,用空集合替代 null,对 java 得接口也适用。
    jhdxr
        181
    jhdxr   31 天前
    @wangkun025 技术能力有待提高。
    wangkun025
        182
    wangkun025   31 天前
    @jhdxr 嗯。确实。
    meiyoumingzi6
        183
    meiyoumingzi6   31 天前 via iPhone
    其实不合理,容易给调用方增加心智负担
    nemo0718
        184
    nemo0718   31 天前
    我是后端开发,我倾向于使用固定字段返回,为空时也返回对应的 key,即: { "A": "", "B": null }
    ,特别是那些对外提供的接口,除非能保证提供的文档完整,字段能全部列出来说明,不然作为调用方会很麻烦。
    weixiangzhe
        185
    weixiangzhe   30 天前 via Android
    对于集合要么不返回 要么返回[]或{},返回 null 的话很容易出 bug
    q8164305
        186
    q8164305   30 天前 via Android
    可维护性难道不是高于性能,扯性能的是在搞笑么?你要说安全性高于可维护性还能理解,我是倾向于第二种的
    Rhonin
        187
    Rhonin   30 天前
    @trlove 你可能不知道啥叫规范,也不知道屎山是从十几年前堆起来的,张口就人身攻击的,确实不该回复你。
    1  2  
    关于   ·   帮助文档   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1290 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 19:06 · PVG 03:06 · LAX 11:06 · JFK 14:06
    ♥ Do have faith in what you're doing.