今天发生一个离谱的问题
我是个前端开发,有一个列表接口,本来有数据,后面突然列表没了,前端逻辑没动过
我看了看接口,发现接口正常,里面列表数据都在,在控制台打印数据也都正常
最后打印列表字段 rows
发现是 undefined
,这才发现列表数据的 key 变成了 data
后端反馈是有两种数据结构,一种是有分页一种是无分页
有分页的接口返回 rows
,无分页的接口返回 data
后面甚至提出前端在响应拦截器判断一下,有 rows
的话拿 rows
,没有的话拿 data
我觉得很离谱,在我的认知中,我认为后端返回的数据要保持一致性
类似这样
interface ResponseData { code: number data: Array | Object // 这里就大概表示一下可以是列表数组可以是对象 total?: number // 需要的话返回 message: string }
争论半天后端大概意思是:“一般都是这样的,分页和其他查询结果有差异”、“没有必要改 不然看不出来 分页和部分也的区别了”、“你现在没数据了你能第一时间知道是接口改成不分页的了”、“这个框架都几十年了一直都是这样” ...
最后虽然也改成统一的了
但我我对这套说辞是:???
想请教一下大家,你们对接的数据结构也是不统一的吗?哪种方式更好呢?
![]() | 1 lucasj 278 天前 ![]() 有分页 GET /users/page 和无分页 GET /users 各一个接口不就行了吗 |
2 vampuke 278 天前 ![]() 懒得争论 直接 rows || data |
![]() | 3 ltaoo1o 278 天前 意思是,同一个接口,从有分页改成无分页,并且数据结构变了,还没有通知你,如果是这样,那肯定是后端的问题。 如果是两个列表接口,分别用于有分页和无分页,那这个正常。 我感觉你说的是情况一,后端的锅。 |
![]() | 4 pike0002 278 天前 这个没有统一规范,根据具体需求来说。本身这个规范也是由前端后端协商好的,不是由任意一方认为应该怎么就怎样的。所以提前协商好就行。 但是根据描述,这里的问题应该是出现在之前工作,然后现在不工作了?这个按你描述后端也没动?框架几十年了都一样。所以这里应该还是有一方动了?? |
5 kakki 278 天前 就算判断一般也不用 key 来判断 要么就分接口 要么就请求的时候通过查询参数是否请求分页 要么就一律统一返回一个格式,limit 设置个特殊标记表示无限比如 -1 不过嘛...最终还是看你们自己的约定来处理 |
![]() | 8 imba97 OP @ltaoo1o 是的,可能也是误操作改了啥,这个不清楚。但前端排错很麻烦,因为第一时间根本意识不到是 key 变了,看到有数据就检查一下一环了,后面的排错纯粹是浪费时间 |
![]() | 9 imba97 OP @pike0002 确实没有统一的规范,但有些接口是 rows ,有些接口是 data ,甚至要前端做兜底判断,给我的感觉还是比较怪的 不是之前的工作,就是刚才发生的,兼职工作 |
![]() | 12 importmeta 278 天前 无所谓, 心情最重要. |
![]() | 13 imba97 OP @importmeta 确实 |
![]() | 14 lucasj 278 天前 ![]() 结论:有分页和无分页本质上是不同的接口,所以数据格式不需要保持统一。统不统一都可以。后端给什么用什么。或者按接口文档上写。 感觉 OP 像是新手。其实不用纠结这些细节,能跑就行。项目代码早晚都是屎山。理解屎山,超越屎山。 |
![]() | 15 IvanLi127 278 天前 很离谱,这后端平常靠空指针异常来判断上游是否迭代? |
![]() | 16 donaldturinglee 278 天前 ![]() 我记得我做的时候无分页和有分页也是两个接口, 我会在文档上写清楚返回的数据结构该是什么样的, 以文档为准 |
![]() | 17 imba97 OP @lucasj 笑死,早晚都是屎山确实不假。我自己的项目我是尽量避免写成屎山,公司项目就没办法了。我之前其实接受了,但今天排这个错排的心累,做了一些无用功。新手也确实是新手,感觉学不完 |
![]() | 18 imba97 OP @donaldturinglee 但你架不住像我这种,后端可能误操作改了啥,然后前端疯狂排错,最后发现 key 变了,排错排了个寂寞的情况 |
![]() | 19 donaldturinglee 278 天前 @imba97 没有文档的前端兼职做起来是这样的, 全靠猜 |
![]() | 20 imba97 OP @donaldturinglee 文档是有的,虽然更新不及时 |
![]() | 21 wangritian 278 天前 ![]() “有一个列表接口,本来有数据,后面突然列表没了” 这件事重要的不是定义成什么样,而是后端改了东西不告诉前端 你需要强调以后任何修改都必须先协商,至于改成什么样,建议照顾下没水平又脾气大的那方 |
![]() | 22 imba97 OP @wangritian 好像是误操作之类的改了,后端可能也不知道。但我想如果数据格式一致的话,顶多就是分页失效了,还好发现点。我找半天发现是 key 名字换了这不扯淡么 |
![]() | 23 donaldturinglee 278 天前 @imba97 下次多做点沟通试试, 向下兼容一下. 我习惯做了接口改动都和前端说一下, 让前端记得重新看一下文档 |
![]() | 24 imba97 OP @donaldturinglee 好嘞 |
26 |
![]() | 27 RyougiShiki 278 天前 应该统一结构 |
28 dcsuibian 278 天前 分两种结构啊,就像这样: interface ResponseWrapper<T> { result: T message: string code: number timestamp: number } interface PageWrapper<T> { data: Array<T> pageNumber: number pageSize: number total: number totalPages: number } |
29 dcsuibian 278 天前 如果是一个普通的项就是 ResponseWrapper<T> 如果是个列表就 ResponseWrapper<Array<T>> 如果是分页数据就 ResponseWrapper<PageWrapper<T>> |
![]() | 30 ashing 278 天前 这跟有没有分页其实没有关系吧,统一字段返回即可。例如下面这种: ```json { "list": [], "total": 0 } ``` |
![]() | 31 sgiyy 278 天前 后端真没必要在 response 里多加一个 rows 的字段啊...不过如果是老项目的话可能是之前代码里的约定了,他就这么接着写了,那尽量就不要改了;新项目的话找他重新约定下或者让前后端 leader 谈一下吧 |
![]() | 32 wolfie 278 天前 考虑到你的表述水平,建议你听你们后端的。 |
![]() | 33 heimoshuiyu 278 天前 大家都是草台班子,吵得过就听你的,吵不过就乖乖写判断逻辑 |
34 SPACETYPEZERO 278 天前 之前遇到过差不多的情况,后端如果数据为空返回前段 JsonObject ,如果有数据返回 JsonArray ,很难评哇,本来是分装好的网络请求库的,现在要手动 Json 解析了。 |
![]() | 35 demonzoo 278 天前 我们是前后端都用 typescript ,用统一的 schema types 管理数据类型,很安逸。。。后端如果 api 接口变了的话,build 的 CI 也会挂,PR 根本 merge 不了 话说像你说的这种后端改动已经属于 breaking change 了,既没有做兼容又没有通知前端更新,属实草台班子 |
36 MarsCloud 278 天前 不管数据是什么,一般默认都会要求服务端直接统一格式以及统一字段名处理; 统一字段名,泛型比较方便处理,多个字段命名,那么就得定义多一个字段来处理 |
![]() | 37 aiqinxuancai 278 天前 你们怎么周六还上班 |
![]() | 38 XCFOX 278 天前 接口格式一般听后端的,但是文档一定要写清楚。 最好是加上 OpenAPI/tRPC/GraphQL 确保端对端类型安全,能避免很多接口对接的问题。 |
40 klzy 278 天前 插一句题外话,是不是直接拿 ruoyi 或者其他基于 ruoyi 修改的框架做的系统,因为我对这个操蛋的地方有一点点印象.... |
42 ruxuan1306 278 天前 赞同二楼,写个`rows || data`兼容就行了,来回 battle 加发帖内耗两三小时就过去了。 大多数系统活不过一两年,人生那么多重要的事,还是多花时间汇报吹 b 向上管理。 |
![]() | 44 imba97 OP @SPACETYPEZERO 难顶 |
![]() | 45 imba97 OP @ruxuan1306 也没,后面拉了个会,后端分分钟改完了 |
48 metalvest 278 天前 via Android OP 想的是如果数据结构统一了,至少就可以避免这次前端做无用功的排错。但后端想的是幸好没统一,不然可能很久都发现不了这次误操作。 |
50 dayeye2006199 277 天前 via Android 问就是 graphql |
51 zerovoid 277 天前 via Android 加个判断的事情,除非有代码洁癖,没有让前端自己去拉数据库增删改查就不错了。 |
![]() | 52 lijianan 277 天前 https://zod.dev 用起来,数据结构不对直接拦住,UI 降级一下把错误展示出来 |
![]() | 53 xuanbg 277 天前 其实 OP 说的是原先不管是数组还是对象,都放在 data 字段。现在后端改成 data 字段只放对象,数组则放到 rows 字段。这种无厘头行为给 OP 带来了困扰,原先写好的获取数组的接口都要相应修改成取 rows 字段才能正确显示数据。 这不是赛博画蛇添足么? OP 你应该问下后端用 data 返回数组判几年? |
![]() | 54 zhaokun 277 天前 是否启用分页我一般给个参数让前段控制,返回结构是一样的 |
55 lcbp 277 天前 是否分页为什么要换接口,为什么要两种不同的数据方式。后端接口支持传递分页参数(页码、每页数量)不就行了吗? { code: 200, message: '', data: 列表数据 Array<item>, meta: { pagination: {当前页码、本业数据条数、是否有下一页、记录总数} } } |
56 tabc2tgacd 277 天前 这里一个关键是:事先有没有做出这样的约定?如果有作出约定,那是前端的锅,如果没作出约定那就是后端的锅。至于是不是合理,反而不重要。 |
![]() | 57 9dP06m83vIV00l72 277 天前 升高维度:请他一根烟 或 一瓶可乐,建议改成一致, 不就双方都很愉快嘛 |
![]() | 58 a33291 277 天前 正好前不久遇到过第三方类似的设计 作为后端,我觉得这就是后端设计问题,况且统一的数据结构对后端来说也更简单 |
59 laminux29 277 天前 ![]() 看了楼上的评论区,深刻反映出:我国软件水平还非常低,低还普信。 OP 的考虑是对的,对于专业的软工,正确的做法是,只用一套数据结构,在数据结构内部,通过 pageCount 来判断是否有分页。如果无分页,pageCount 为 1 ,表示只有 1 页数据。如果大于 1 页,表示有分页。 楼上那些 2 套接口、甚至 rows || data ,全都是瞎搞。 |
60 november 277 天前 via iPhone 有没有改,直接看 git commit 不就有了? |
61 lscho 277 天前 我是后端,这个问题从表面上看肯定是后端的锅,同一个接口出来两种不同结构的数据就是不符合规范的。 从根源上说你们整个组都有问题,应该先定规范再开发,而不是中间遇到问题再协商。 即使是遇到问题需要协商,也需要有一个拍板决定的人来决定怎么处理。 |
![]() | 62 simo 277 天前 往业务链上游走,先从产品经理开始,一渣到底,折磨死后端 |
![]() | 63 chairuosen 277 天前 我的做法:反正我不该,你爱咋咋地,你找谁都没用 |
66 iOCZS 277 天前 无脑 list 。。。。 |
![]() | 67 imba97 OP @lcbp 也不是分页需要换接口,是调用有分页的接口返回的是 rows 。所以这次的情况是后端可能不小心把有分页改成无分页的数据结构,对于前端排查来说看到接口有数据就会过掉,根本注意不到是 rows 还是 data ,后面做的排错都是无用功,这就让我觉得很难受 |
![]() | 68 imba97 OP @tabc2tgacd 是这样,之前把有列表的接口改成 rows 我虽然感觉很奇怪但也接受了。这次问题是后端可能不小心改错了,把有分页改成无分页数据结构了,所以 rows 变成 data 了。前端这边排错一般看到接口有数据就排查别的了,根本注意不到 key 是不是变了,后面的排错都是无用功浪费时间。如果都统一了至少不会有这个问题,顶多可能是分页功能失效了,这样前端也能更直观的看出来问题 |
![]() | 70 vishun 277 天前 后端用的 ruoyi 框架,就是这样,主要问题是后端改了没告知前端的问题,定义一个和两个类型没什么区别。 |
72 digimoon 277 天前 能一样就一样我觉得没啥问题,谁愿意每个螺丝孔都用不同的螺丝 |
73 kakki 277 天前 @laminux29 有的接口在查询参数不同的情况下,返回 pageCount 为 1 就是无分页,有无分页部分接口应该直接在概念上定义好,而不是根据敲一棍子看看出什么 shit 来判断。 |
74 JayLin5 277 天前 理论上来说肯定是一致最好,但是实际开发过程中,看谁强势一点哈哈哈,能叼的过他直接开叼,叼不过默默改前端加个判断,都是草台班子,对于老板来说项目跑起来就行,反正等你离职之后痛苦的是下一位,然后下一位就开始骂祖传代码。 |
![]() | 75 panbeta 277 天前 服务端刚毕业吗? 这水平做外包都勉强 |
77 kakki 277 天前 @laminux29 我又看了一下上下文,很明显我们讨论的完全不是一个东西~ 我们讲的是“相同实体的有无分页数据接口”,你讲的是”分页接口的有无分页判断“,很明显,这不是一个东西。 |
78 jianghu52 277 天前 我说头像怎么这么熟悉呢,原来是 B 站的博主啊。加油。 |
![]() | 79 cuberlzy 277 天前 via iPhone 无所谓。争赢了去下家公司还得争 |
![]() | 85 jiangzm 277 天前 分页和列表肯定都要存在不能为了结构相同而直接简单粗暴统一返回结构。要统一的时候不同数据分页接口的结构和不同数据列表接口的结构。 如果后端是不小心改了原接口的返回结构, 那 100%是后端的锅,哪怕原来的接口不合理是代码逻辑很糟糕也不能随便改。 如果是新接口前端通用请求预期的结构和后端返回的不一致, 那属于前期沟通和前端自测有问题。 另外不建议把分页和列表结构放到一个类型定义中,定义 PageData 和 ListData 即可, 通用接口请求方法根据入参(有无分页参数)很容易区别响应类型。 |
![]() | 86 ooo4 277 天前 以前我也觉得后端返回的数据结构应该保持一致,直到后面被安排到其他项目组,里面的后端都是公司呆了 10 多年那种,接口写的十分的丑陋,什么拼音啊,额外字段用什么 xxx1 ,xxxx2 ,xxxx3 前端根本用不上,虽然代码很恶心,但管他的,说不定明年你就跑路了 |
![]() | 88 wangtian2020 276 天前 关于页面需不需要分页这个问题我已经找到真理了,就是统一只提供一个分页接口。想要不分页? pageSize:9999 了解一下,一个接口按你需要随你掉 对接后端接口最怕的就是对象结构会变的,这是对后端最基本的要求,接口对象的结构不能变,而且要统一。别信他瞎几把扯,设计混乱的接口能不能用,能用也能跑,代码和人有一个能跑就行,代码可以是屎山不是我接手就没意见。 不,我也是有意见的,我这个人就是见不得设计的屎的接口。 直接怼后端,别惯着这种菜逼 |
![]() | 91 keepfun 276 天前 盲猜后端用的是 ruoyi |
92 nanpu 276 天前 ruoyi 分页和不分页返回结构是不一样的,后端改错了 |
![]() | 93 Yanlongli 276 天前 不管是统一还是不统一其实都无所谓,但是前提要提前沟通,不能直接就换了不通知。 今天还是 rows ,第二天变成了 data ,第三天变成了 list ,第四天换成 records ,第五天换成 elements, [] |
94 BG7ZAG 276 天前 如果是 app 端强类型语言的话,这种动态相应类型直接爆炸 |
95 mark2025 276 天前 @wangtian2020 统一用分页的类型,不分页就当是 LIMIT 1 OFFSET 0 的特例嘛。 |
![]() | 97 imba97 OP @fenglangjuxu 确实是 ruoyi |
![]() | 98 imba97 OP @BG7ZAG 最开始用的 TS ,中间我退出了一阵,回来发现成了 any script ,天塌了。我还配了 eslint + git hooks ,结果直接给我绕过去 |