比如和后端商定好了,返回的接口格式是: { "A": "", "B": [{}, {}] } 这时候后端说了,B 的数据有时候没有,如果没有的话就直接返回{A:""} 我让他返回{"A":"***", "B":[]}
哪种方案好?
101
yaphets666 2021-01-27 09:17:53 +08:00
其实这是无可争议的.你想就知道了.关系型数据库里头,一个字段没值,是空呢,还是这条数据没这个字段?
|
102
bakujin 2021-01-27 09:18:28 +08:00
其实我们这么做是为了节约带宽资源
|
103
Twain 2021-01-27 09:21:40 +08:00
应该先思考应不应该返回,而不是你觉得好不好处理,这个东西本来就没有,为什么还要给你字段呢?先问该不该
|
104
zhuweiyou 2021-01-27 09:28:54 +08:00
B 没有 不返回, 对我来说 更好判断.
如果返回个 [], null, {} 或者 其它值, 我还有心智负担, 它到底空的时候是啥. |
105
anson2017 2021-01-27 09:31:28 +08:00
我觉得都一样,无非是判断 undefined 还是判断空数组的问题
|
106
Zoomz 2021-01-27 09:38:51 +08:00
后端是用 Java 写的吗,如果是用 DTO 返回的话理论就是第二种(但是 B 返回的为 null ),除非它使用 Map 装的。。
|
107
shew5689 2021-01-27 09:40:14 +08:00
if("key" in data){} 判断不就 ok 了吗~ 反正合不合理,总有人妥协,不是服务端处理,就是前段处理~
|
109
justsosososo 2021-01-27 09:47:16 +08:00
没什么合理不合 你不干就后端干 你两都不想干就招个中台来干
|
110
zhangshine 2021-01-27 09:51:35 +08:00
防御性编程,即使后端返回第二种 ,前端也应该判断会不会出现第一种情况
|
111
bfdh 2021-01-27 09:53:16 +08:00
@anjianshi 前端代码复杂起来不好保证所有处理这个字段的地方都妥善处理了空值,而后端只要在返回的地方处理一次就好了。
换成下面这种说法是不是也没错? 后端代码复杂起来不好保证所有处理这个字段的地方都妥善处理了空值,而前端只要在接收的地方处理一次就好了。 |
112
pangleon 2021-01-27 09:53:58 +08:00
这种情况我见过,
公司部分项目约定后端字段为 null 不返回 实际需要看你们的约定,没什么合理不合理,看约定和场景而已 别这么死脑筋,你觉得用不到可能人家一个接口对接好几个前端,别人需要 |
113
yogogo 2021-01-27 09:55:33 +08:00
前端应该也要所有情况都要考虑到,这样就不用怕后端返回什么类型了
|
114
zishaofei221 2021-01-27 09:58:33 +08:00
约定好就行了。你不同意,就找他老板商量。
不返回可能是偷懒没 Vo,直接 map 了个数据给你。 |
115
no1xsyzy 2021-01-27 10:05:15 +08:00
应符合语义。
这样说有点不明不白,还是解释一下: 打个比方,API 请求物品栏内容。那么,一个有物品栏但物品栏为空的角色,和一个没有物品栏的角色,分别是 [] 和 null 但 null 和不存在此 key 应当是同义的(根据 JSON merge patch RFC )。 说不定还是要推荐一下 GraphQL 之类请求方指定 spec 的方案(中台…… |
116
caijihui11 2021-01-27 10:06:23 +08:00
这个取决于前端同学的看法,遇到迷惑可以问一下后端同学具体判断逻辑,接口文档只会提供一份最全的接口返回,后端大部分不返回的一些字段是用不到的,能用到的也是有前置条件。
前置条件可能是: 1 某个字段 是否 undefined 2 固定返回某个值的状态 |
117
Yano 2021-01-27 10:06:48 +08:00
后端序列化 json 的时候,可以指定空或 null 值直接不返回的。
即使后端返回了,你也应该防御编程,判断一下吧。我写接口,前端所有的参数都不信任的,都要校验合法性…… |
119
yaphets666 2021-01-27 10:12:48 +08:00
@justsosososo 当然不是了...合理就是合理 不合理就是不合理 一个字段没有值的时候如何处理,参考关系型数据库...
|
120
cmostuor 2021-01-27 10:18:50 +08:00
估计没有统一的规范约束着
|
121
guyeu 2021-01-27 10:24:06 +08:00
这种难道不是前后端商议通信协议,共同定义协议( protobuf 、json scheme 、dsl ),分别生成基于前后端技术栈的通信层数据结构和基本逻辑,然后基于生成的代码编写具体的业务逻辑,这个时候可能是空就判空,不可能是空就不判空?
|
122
trlove 2021-01-27 10:26:02 +08:00
@laminux29 1.不敢苟同您的加强鲁棒性设计。100 个字段出现 100 个状态字段再去分别表示状态,在我看来就是过度设计,滥用设计模式。完全是为了套设计模式而设计,增加了操作流程,延长了操作线。
2.不加状态字段,判断数据本身,如果发生错误,无非就是后端返回了前端没判断,后端没返回(如果前端判断了字段,即使后端出错,前端也不可能出错),那问题就回到了前端的判断问题。所以只需要前端看下代码有无判断就能立马知道是不是后端的错。再退一万步,您认为加了判断状态字段,排查快,不费时费力。但是您忽略了后端操作的错误性。如果上百个字段,您就能保证后端不犯错误忘记改某个字段状态?出现了问题,您能百分百确定是前端没判断 ,还是后端数据改变的不全?不还是得一个个去排查。而且还得是对着数据一个个看,看看哪个数据状态维护错了。您的加强鲁棒性吧问题前置到数据的初始化状态了,排查起来只会更复杂。本身并没有解决您说的犯错误问题。再退十万步,一个系统要想健壮就完全靠拼凑设计模式?就难道没有自测,测试专测,上线前回测,以及灰度?您所说的犯错误的情况在这些测试阶段就能被发现,解决您问题的是测试的流程而不是您的设计模式解决了犯错误的本质。 3.个人理解任何设计模式的流行必然有其合理性。但我认为合理的利用设计模式可以锦上添花,不合理的套用设计模式只会是增加复杂度,并不能实质性解决问题。 |
123
lonelymarried 2021-01-27 10:26:31 +08:00
这真那后端没办法,一般如果我的项目,前后端都是我写,就自由多了。这不,后端又出问题了,app 都上线好久了,中途加了个需求,后端就出问题了,昨天反映了,今天还没答复。我是写过 java 后端的,知道这东西也就分分钟的事。没办法,公司的后端就这么搞。自己前后端都学学吧。
|
124
GoNtte 2021-01-27 10:26:51 +08:00
第二种好 看返回就知道是数据结构了
|
125
0x666666 2021-01-27 10:32:28 +08:00
阿里云官网的做法是:如果 key 的 value 是 null,就不会返回 key 。
第一:不会返回无意义的数据。 第二:省流量(虽然省不了多少)。 第三:如果要后端强制 key 的 value 是 null,要返回一个 key: "" 或 key:[],对于后端来说需要对每个属性都要进行初始化赋空值不说,还要在参数映射完以后,再做一次 null 检查,把 value 是 null 的 key 设空值。这个过程是一个比较麻烦并且没有必要的流程,而且还浪费服务器性能。 第四:和楼上的老哥说的一样,前端不能把命运完全交给后端,自己也要做好空值判断,key 没有的情况。 综上所述,我觉得前端做好对应的判断即可,没必要后端去做这些操作。 |
127
Sapp 2021-01-27 10:35:59 +08:00
单个不存在的时候返回 null 、
数组不存在返回空数组 或者你干脆用 typescript,让后端搞个 OpenAPI,写个 node 读取 json 数据自动生成前端接口函数,顺带写上 interface,不就没这个问题了,返回的啥都无所谓,只要他定义好了你这边就有提示 |
128
kifile 2021-01-27 10:36:05 +08:00
我会选择第二种,原因是 null 也是一种特殊情况啊,null 和 [] 其实是不等价的,如果业务逻辑中的确是空数组,那返回空数组无可厚非,而如果业务逻辑中应该是 null ,并且使用一些 json 库序列化 null 值,库会帮你删除掉 null 的 key
|
129
notejava 2021-01-27 10:37:55 +08:00
前端喜欢第二种,后端喜欢第一种,大家都不想多写几层判断代码
|
130
sevenzhou1218 2021-01-27 10:42:56 +08:00
关系好,都不是事,关系不好,死怼。
|
131
killerv 2021-01-27 10:43:53 +08:00 5
我很惊讶那么多说第一种的,B 是个 list,B 的数据没有也只代表 list 为空,不应该没有 B 这个属性,这是两个概念。
举个例子:接口返回的数据表示某个人的一些信息,有个字段是 friends,类型是 list,他可以没有一个 friends,可以是空数组,但是作为人他一定具备 friends 这个属性。 |
132
kltt22 2021-01-27 10:46:01 +08:00
你给我个最全的字段,就啥事没有,就怕你现在返回的没有,一会又有了。上次对了个 java,本来说好了是最全的,后来实体类报错了,发现默默的多了几个字段。这玩意后端自己都控制不住的话,还是所有字段都返回吧。
|
133
bootvue 2021-01-27 10:54:37 +08:00
凡是为空的 最好都不返回那个字段
按照某些前端的逻辑 B 是集合 返回个空集合 [] , 那 B 要是个 object 返回啥 : null 还是 {} , B 要是 number 返回啥: null 还是 0 完全都是扯淡 不返回意义更明确 前端更好判断 typescript 约束更有意义 |
134
asAnotherJack 2021-01-27 10:56:26 +08:00
@kltt22 #132 这种应该放在接口文档里
|
135
andyli9449 2021-01-27 10:57:52 +08:00
把问题简化一下,比如一个用户属性。 有 email 字段,且并没有被设置。那么返回的格式应该是 { "email": null } .还是 { "email": ""}; 。API 文档中返回值的定义这个值应该是 string, 但返回 null 就和文档不符。但没有设置,email 值就是""也挺奇怪。比如年龄未设置 该返回时 {"age":null} 还是 {"age": 0} ,API 文档 age 字段肯定应该是数值(Int/Number) 。
|
136
est 2021-01-27 10:57:57 +08:00
如果没有的话应该返回: {"A": "", "B": "null"}
|
137
cyrbuzz 2021-01-27 11:08:24 +08:00
这个...我怎么觉得返回`{A:""}`其实也不省流量,如果这个接口在一次普通用户访问中只会调用固定的几次,这样前端本来可以写成`response.B[0]`的代码现在要写成`response.B && response.B[0]`,这样不仅没有省流量,还有可能会阻塞首屏加载的嘞= =...
|
138
jrtzxh020 2021-01-27 11:11:00 +08:00
@whileFalse 一个?那是一百几十个属性,每个接口都要都不同。String 返回 null Array 也返回 null,前端没有强类型,但是前端变量也有数据类型的好吗
|
139
bbao 2021-01-27 11:11:14 +08:00
基本原则:后端的做法好,没有就不传,节省网络传输流量贷款的浪费。
可能一个请求会很大,这样做好处多,前端做校验处理啊; client -> server 后端在 rpc 到其他服务拿回来的数据,有变化肯定后端已经做好了处理。 前端也要相应的咯。 |
140
andyli9449 2021-01-27 11:12:10 +08:00
@killerv friends 没设置返回[]可以,我想知道如果年龄(age)这个属性没有设置应该返回什么 0 或者是 null 吗?
|
141
midtin 2021-01-27 11:12:59 +08:00
服务器计算资源和带宽流量永远是最昂贵的资源,在合理的情况下减少后端的判断处理,通过输出更少的数据来节约流量,我认为是没问题的
|
142
lhx6538665 2021-01-27 12:30:53 +08:00
无所谓,怎样都行,这个问题你也可以问下自己,后端需要你传这种数据,你要怎么传
|
143
killerv 2021-01-27 12:33:04 +08:00
@andyli9449 如果是我的话,我会用 null 。
|
144
wangkun025 2021-01-27 12:40:02 +08:00
前端是需求方,前端说啥就是啥。
这事后端没发言权。 |
145
back0893 2021-01-27 12:41:28 +08:00
protobuff?
导致的没有缺失? |
146
killerv 2021-01-27 12:42:40 +08:00 2
扯到带宽和流量就有点牵强了吧,{"B": []} 和 {} 能差多少流量?网络发展到这个时代,这个成本基本上可以忽略不计。规范是很重要的,语意不明的表达会增加很多沟通和开发成本。
|
147
clf 2021-01-27 12:50:36 +08:00
像 SpringBoot 的话,很可能是直接配置了 Jackjson 不输出 null 值。先和他确认一下是不是写公司后端基础框架的人规定的。如果需要完整的数据项,可以考虑直接和对方沟通。
我觉得比较大的可能性是为了少写面向前端返回结果的 ViewModel,直接用字段最全的类,从数据库里直接查需要的字段填充,数据库里为 null 的值可能填充了一个 null,所以这个字段被当作是无效字段直接被 json 序列化工具砍掉了。 |
148
cumt21g 2021-01-27 13:07:16 +08:00
应该保持字段的固定
|
149
jhdxr 2021-01-27 13:25:43 +08:00
v2ex 的水平下降的有点严重啊。。。无脑站第二种的居然这么多?
@killerv 你都能想到语义了,有没有想到不存在 b,或者 b 为 null,与 b 的值为[]这两者的语义是不同的? 而且无论后端最终写成啥样,前端那边难道不应该始终检查一遍吗? |
150
gggxxxx 2021-01-27 13:26:11 +08:00
都什么年代了,还提省流量和服务器开销......
新观念,第二种方法保持字段的固定有很多优势,所付出的成本(开发精力和硬件资源)微不足道。 坚持第一种方法太古典了,其实并没有省事。出了问题后端还不是要一起排查。 |
151
jhdxr 2021-01-27 13:26:35 +08:00
@wangkun025 你可能对需求方这三个字有啥误解
|
152
jason19659 2021-01-27 13:27:38 +08:00
第一种,可选字段不判空是逻辑错误
|
153
vincentxue 2021-01-27 13:51:13 +08:00
我全端通吃, 我的规则就是:
1. 我支持你的想法。我的做法是这样,如果 B 是一个 Object,那么为空的时候返回 null,如果是一个 Array,为空的时候返回 []。 2. 所有的字段都会存在,不允许有时候有 B 有时候没 B 的情况出现。 这种情况下,Web 、iOS 、Android 都不会出问题,特别是 Android,Android 用 Gson 如果不做额外的工作,只要一个字段没有就会抛异常。 我个人认为服务端某种意义上就是为客户端提供服务的,我写接口的时候一直都是本着方便别人麻烦自己的心态。如果双方出冲突,后端应该让步给前端。我最烦那种偷懒的人,明明知道那样做比较好,但是麻烦点,就各种推脱不做。 |
154
killerv 2021-01-27 13:55:28 +08:00
@jhdxr 同一种类型,不应当存在某个特殊对象不存在 b 的可能性。Json 这种系统间交互的数据格式,不应该存在相同类型但是数据类型不统一的情况。你说的前端始终检查一遍就是额外的成本,如果都按照规范来,就不存在这个问题。
|
155
killerv 2021-01-27 13:58:07 +08:00 1
@jhdxr 你这种用冗余代码兼容各种异常情况,看似健壮,实际上是对规范的破坏,带来的是沟通、维护成本的巨大提升。如果前后端都按照规范来,前端根本没必要校验这种情况。
|
156
baixixi 2021-01-27 13:58:42 +08:00
就这么点事,前后端都是一个 if else 的事,有那么难吗
|
157
codingguy 2021-01-27 13:59:52 +08:00
不返回 B 也没问题呀。前端直接 const list = response.B ?? [ ] 就好了
|
158
oddisland 2021-01-27 14:06:57 +08:00
res?.B ?? [ ]
|
159
leeyom 2021-01-27 14:10:26 +08:00
通常是第二种,第二种数据结构具有完整性,其实这种不管是前后端,如果做的严谨一点的话,前后端都要做判空处理
|
160
wh1012023498 2021-01-27 14:19:15 +08:00
又到了前后端为了方便不方便争论了,前端方便后端就不方便了,后端方便前端就不方便了。
所以这不是技术问题,这是话语权之争。 |
161
q1angch0u 2021-01-27 14:24:20 +08:00
月经贴……
|
162
dm4927 2021-01-27 14:24:44 +08:00
啊,这问题我熟,之前驻场一家公司就是这样的。
后端接口只返回存在值的字段,然后出现了以下问题,之后改成了所有值都传。 第一是,有些接口返回的是 Object 套 Object 的,大概三四层,这就导致了,前端需要一层层的处理。 第二是,因为项目比较大,陆陆续续来了很多人,然后每来一个人,都要和他沟通说明下为什么有的时候有这个字段,有的时候没有,而由于业务原因,好多时候还需要讲一下触发这个字段的方式,沟通成本直线飙升。 |
163
salmon5 2021-01-27 14:29:39 +08:00
说省流量的,不应该带个狗头吗
|
164
Hoshinokozo 2021-01-27 15:07:41 +08:00
作为前端,肯定是倾向第二种的,保证数据的一致性能减少大量的的沟通成本和 bug 几率,但是看站内后端老哥的回答第一种在某些特殊情况下也是有一定的道理的,所以说到底这事还是在于沟通,前后端提前商量好,到时候出问题分锅也有依据。
|
165
SyncWorld 2021-01-27 15:45:21 +08:00
一开始返回的时候用直接扔到 map 里返回,过滤了 null 的 key,直到有一天,连接 ORacle 发现直接扔到 Map 里返回到前端的字段全 TMD 是大写,我的强迫症迫使我又封装成对象返回,这件事充分说明怎么返回都无所谓,关键还是协商问题
|
166
alreadytaken 2021-01-27 15:48:18 +08:00
最佳解决方案是有的。
背景:最近在捣鼓 vue3+ts 写新项目。 使用 openapi-typescript 连后端给的 swagger,前后端 require,response 定义完全一致,完美解决。 |
167
THESDZ 2021-01-27 16:06:04 +08:00
我建议返回
{"A":"val","B":null} 因为 null 和[]完全是两码事,根据后端说的话: B 的数据有时候没有 即 B 此时应该为 null 而关于属性不固定等,应该看文档 实际上仍然是协商的问题 |
168
xaplux 2021-01-27 16:12:31 +08:00
后端返回的 json 格式估计设置了忽略值为 null 的字段,前后端约定好就行了
|
169
qdpoboy 2021-01-27 16:23:35 +08:00
倾向于第二种。
那假如这是一个开放给外部的 api 接口,那会是那种好呢?如果是字段有值才返回,那文档上每个字段是不是都要写上一句,如果有值则该字段返回,否则不返回 |
170
xumng123 2021-01-27 16:43:42 +08:00 via iPhone
restful 的接口定义有 option,前端就要按照两种情况处理,大家可以看大厂的接口,他们不会给你 option 返回[]的。
|
171
wangkun025 2021-01-27 16:46:42 +08:00
@jhdxr 没啥误解。
我是做后端开发的。前端不发 request,我服务器都不开机。 |
172
DogMingDD 2021-01-27 16:47:05 +08:00
这个就是事情谁来做的问题,没有合不合理的问题。
|
173
exonuclease 2021-01-27 17:16:28 +08:00
理论上不是应该实例化一个 entity object 怎么能写出来这种代码的
|
174
calmlyman 2021-01-27 17:26:01 +08:00
各位大佬们写的都是重量级 nb 项目吧?才需要这么省流量吧
|
175
jhdxr 2021-01-27 18:39:02 +08:00
@wangkun025 厉害厉害,你服务器不开机是谁在那监听前端的请求的?莫非人肉 oncall ?一个请求过来你再开机?
|
176
saberlong 2021-01-27 18:47:47 +08:00 via Android
刚好手头就遇到一个场景。大致是中间层汇聚各种内容一起返回。但是只知道 key,以及值是一个 json 。某项 key 内容不存在时,你让中间层实例化也很为难啊,都不知道内容。
|
177
Rhonin 2021-01-27 18:56:50 +08:00
@trlove 大厂的屎山都是香的呗?`有时候可能是单条数据 有时候可能是单字符 有时候可能是数组,`合着您觉着这是合理的,不用辩了
|
178
wangkun025 2021-01-27 19:00:31 +08:00
@jhdxr 阅读能力有待提高。
|
179
trlove 2021-01-27 19:57:26 +08:00
@Rhonin 不好意思,你可能不知道什么是全局设计。也不懂啥叫泛型,不知道啥叫兼容。你直接说你懒得在前端做判断不就得了,还觉得不合理。不合理您倒是给出您的见解,并解决问题。而不是一句暴躁的不用辩了。您这么高贵,都不辩,那您在在个这个主题下发什么言,原来 v2 的某些前端就这个水平。另外你不认可的设计就说人大厂的就是屎山,我只能说您水平实在是高。拜拜了您嘞
|
180
jimrok 2021-01-27 20:14:07 +08:00
对于集合,接口永远不要返回 null,用空集合替代 null,对 java 得接口也适用。
|
181
jhdxr 2021-01-27 21:13:07 +08:00
@wangkun025 技术能力有待提高。
|
182
wangkun025 2021-01-27 21:17:31 +08:00
@jhdxr 嗯。确实。
|
183
meiyoumingzi6 2021-01-27 21:22:25 +08:00 via iPhone
其实不合理,容易给调用方增加心智负担
|
184
nemo0718 2021-01-27 23:03:23 +08:00
我是后端开发,我倾向于使用固定字段返回,为空时也返回对应的 key,即: { "A": "", "B": null }
,特别是那些对外提供的接口,除非能保证提供的文档完整,字段能全部列出来说明,不然作为调用方会很麻烦。 |
185
weixiangzhe 2021-01-28 09:07:15 +08:00 via Android
对于集合要么不返回 要么返回[]或{},返回 null 的话很容易出 bug
|
186
q8164305 2021-01-28 10:17:32 +08:00 via Android
可维护性难道不是高于性能,扯性能的是在搞笑么?你要说安全性高于可维护性还能理解,我是倾向于第二种的
|