V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
imba97
V2EX  ›  程序员

关于今天给前端返回数据的结构的争论

  •  
  •   imba97 ·
    imba97 · 2 天前 · 4361 次点击

    今天发生一个离谱的问题

    我是个前端开发,有一个列表接口,本来有数据,后面突然列表没了,前端逻辑没动过

    我看了看接口,发现接口正常,里面列表数据都在,在控制台打印数据也都正常

    最后打印列表字段 rows 发现是 undefined,这才发现列表数据的 key 变成了 data

    争论开始了

    后端反馈是有两种数据结构,一种是有分页一种是无分页

    有分页的接口返回 rows,无分页的接口返回 data

    后面甚至提出前端在响应拦截器判断一下,有 rows 的话拿 rows,没有的话拿 data

    我觉得很离谱,在我的认知中,我认为后端返回的数据要保持一致性

    类似这样

    interface ResponseData {
        code: number
        data: Array | Object // 这里就大概表示一下可以是列表数组可以是对象
        total?: number // 需要的话返回
        message: string
    }
    

    争论半天后端大概意思是:“一般都是这样的,分页和其他查询结果有差异”、“没有必要改 不然看不出来 分页和部分也的区别了”、“你现在没数据了你能第一时间知道是接口改成不分页的了”、“这个框架都几十年了一直都是这样” ...

    最后虽然也改成统一的了

    但我我对这套说辞是:???

    想请教一下大家,你们对接的数据结构也是不统一的吗?哪种方式更好呢?

    第 1 条附言  ·  2 天前
    补充一下

    这次可能是后端误操作改了啥,把有分页接口改成了无分页接口,所以 rows 变成了 data

    我想说的是,如果数据结构统一了,至少就可以避免这次前端做无用功的排错
    第 2 条附言  ·  1 天前
    不是后端没通知前端,可能是后端失误改了,把有分页改成了无分页,导致 rows 变成了 data

    所以我想如果统一接口数据结构,最多可能就是分页失效了,这样前端也能更直观的发现问题

    接口一个 key 变了,很难发现。前端一般只看一下接口有数据,就排查别的问题了,这后面的排查全是浪费时间
    95 条回复    2025-01-06 19:54:50 +08:00
    lucasj
        1
    lucasj  
       2 天前   ❤️ 2
    有分页 GET /users/page 和无分页 GET /users 各一个接口不就行了吗
    vampuke
        2
    vampuke  
       2 天前   ❤️ 1
    懒得争论 直接 rows || data
    ltaoo1o
        3
    ltaoo1o  
       2 天前
    意思是,同一个接口,从有分页改成无分页,并且数据结构变了,还没有通知你,如果是这样,那肯定是后端的问题。

    如果是两个列表接口,分别用于有分页和无分页,那这个正常。

    我感觉你说的是情况一,后端的锅。
    pike0002
        4
    pike0002  
       2 天前
    这个没有统一规范,根据具体需求来说。本身这个规范也是由前端后端协商好的,不是由任意一方认为应该怎么就怎样的。所以提前协商好就行。
    但是根据描述,这里的问题应该是出现在之前工作,然后现在不工作了?这个按你描述后端也没动?框架几十年了都一样。所以这里应该还是有一方动了??
    kakki
        5
    kakki  
       2 天前
    就算判断一般也不用 key 来判断
    要么就分接口
    要么就请求的时候通过查询参数是否请求分页
    要么就一律统一返回一个格式,limit 设置个特殊标记表示无限比如 -1
    不过嘛...最终还是看你们自己的约定来处理
    imba97
        6
    imba97  
    OP
       2 天前
    @lucasj 接口不是同一个接口,但返回数据的格式不一样,有的是 rows 有的是 data
    imba97
        7
    imba97  
    OP
       2 天前
    @vampuke 这不奇怪吗,万一需要用 data 的时候,rows 也错误的返回不一样的数据了咋办
    imba97
        8
    imba97  
    OP
       2 天前
    @ltaoo1o 是的,可能也是误操作改了啥,这个不清楚。但前端排错很麻烦,因为第一时间根本意识不到是 key 变了,看到有数据就检查一下一环了,后面的排错纯粹是浪费时间
    imba97
        9
    imba97  
    OP
       2 天前
    @pike0002 确实没有统一的规范,但有些接口是 rows ,有些接口是 data ,甚至要前端做兜底判断,给我的感觉还是比较怪的
    不是之前的工作,就是刚才发生的,兼职工作
    imba97
        10
    imba97  
    OP
       2 天前
    @pike0002 说框架几十年是说的这个框架都开发出来几十年了,都这么用的,不是公司用了这个框架几十年了
    imba97
        11
    imba97  
    OP
       2 天前
    @kakki 接口是不同的,主要想讨论后端最终返回给前端的数据结构,是不是需要保持一致。不然就会出现这种,后端可能误操作改了啥,前端做无效劳动
    importmeta
        12
    importmeta  
       2 天前
    无所谓, 心情最重要.
    imba97
        13
    imba97  
    OP
       2 天前
    @importmeta 确实
    lucasj
        14
    lucasj  
       2 天前   ❤️ 1
    结论:有分页和无分页本质上是不同的接口,所以数据格式不需要保持统一。统不统一都可以。后端给什么用什么。或者按接口文档上写。
    感觉 OP 像是新手。其实不用纠结这些细节,能跑就行。项目代码早晚都是屎山。理解屎山,超越屎山。
    IvanLi127
        15
    IvanLi127  
       2 天前
    很离谱,这后端平常靠空指针异常来判断上游是否迭代?
    donaldturinglee
        16
    donaldturinglee  
       2 天前   ❤️ 1
    我记得我做的时候无分页和有分页也是两个接口, 我会在文档上写清楚返回的数据结构该是什么样的, 以文档为准
    imba97
        17
    imba97  
    OP
       2 天前
    @lucasj 笑死,早晚都是屎山确实不假。我自己的项目我是尽量避免写成屎山,公司项目就没办法了。我之前其实接受了,但今天排这个错排的心累,做了一些无用功。新手也确实是新手,感觉学不完
    imba97
        18
    imba97  
    OP
       2 天前
    @donaldturinglee 但你架不住像我这种,后端可能误操作改了啥,然后前端疯狂排错,最后发现 key 变了,排错排了个寂寞的情况
    donaldturinglee
        19
    donaldturinglee  
       2 天前
    @imba97 没有文档的前端兼职做起来是这样的, 全靠猜
    imba97
        20
    imba97  
    OP
       2 天前
    @donaldturinglee 文档是有的,虽然更新不及时
    wangritian
        21
    wangritian  
       2 天前   ❤️ 1
    “有一个列表接口,本来有数据,后面突然列表没了”
    这件事重要的不是定义成什么样,而是后端改了东西不告诉前端
    你需要强调以后任何修改都必须先协商,至于改成什么样,建议照顾下没水平又脾气大的那方
    imba97
        22
    imba97  
    OP
       2 天前
    @wangritian 好像是误操作之类的改了,后端可能也不知道。但我想如果数据格式一致的话,顶多就是分页失效了,还好发现点。我找半天发现是 key 名字换了这不扯淡么
    donaldturinglee
        23
    donaldturinglee  
       2 天前
    @imba97 下次多做点沟通试试, 向下兼容一下. 我习惯做了接口改动都和前端说一下, 让前端记得重新看一下文档
    imba97
        24
    imba97  
    OP
       2 天前
    @donaldturinglee 好嘞 👍
    pike0002
        25
    pike0002  
       1 天前
    @imba97 嗯嗯,明白你说的意思。如果是统一设计的话确实应该尽量保持数据接口的一致性。这种不一致的管理维护都一定的心智和时间成本。
    lefer
        26
    lefer  
       1 天前   ❤️ 4
    只有我关心今天是周六,应该是休息的吗。。
    RyougiShiki
        27
    RyougiShiki  
       1 天前
    应该统一结构
    dcsuibian
        28
    dcsuibian  
       1 天前
    分两种结构啊,就像这样:
    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
    }
    dcsuibian
        29
    dcsuibian  
       1 天前
    如果是一个普通的项就是 ResponseWrapper<T>
    如果是个列表就 ResponseWrapper<Array<T>>
    如果是分页数据就 ResponseWrapper<PageWrapper<T>>
    ashing
        30
    ashing  
       1 天前
    这跟有没有分页其实没有关系吧,统一字段返回即可。例如下面这种:

    ```json
    {
    "list": [],
    "total": 0
    }
    ```
    sgiyy
        31
    sgiyy  
       1 天前
    后端真没必要在 response 里多加一个 rows 的字段啊...不过如果是老项目的话可能是之前代码里的约定了,他就这么接着写了,那尽量就不要改了;新项目的话找他重新约定下或者让前后端 leader 谈一下吧
    wolfie
        32
    wolfie  
       1 天前
    考虑到你的表述水平,建议你听你们后端的。
    heimoshuiyu
        33
    heimoshuiyu  
       1 天前
    大家都是草台班子,吵得过就听你的,吵不过就乖乖写判断逻辑
    SPACETYPEZERO
        34
    SPACETYPEZERO  
       1 天前
    之前遇到过差不多的情况,后端如果数据为空返回前段 JsonObject ,如果有数据返回 JsonArray ,很难评哇,本来是分装好的网络请求库的,现在要手动 Json 解析了。
    demonzoo
        35
    demonzoo  
       1 天前
    我们是前后端都用 typescript ,用统一的 schema types 管理数据类型,很安逸。。。后端如果 api 接口变了的话,build 的 CI 也会挂,PR 根本 merge 不了

    话说像你说的这种后端改动已经属于 breaking change 了,既没有做兼容又没有通知前端更新,属实草台班子
    MarsCloud
        36
    MarsCloud  
       1 天前
    不管数据是什么,一般默认都会要求服务端直接统一格式以及统一字段名处理;
    统一字段名,泛型比较方便处理,多个字段命名,那么就得定义多一个字段来处理
    aiqinxuancai
        37
    aiqinxuancai  
       1 天前
    你们怎么周六还上班
    XCFOX
        38
    XCFOX  
       1 天前
    接口格式一般听后端的,但是文档一定要写清楚。
    最好是加上 OpenAPI/tRPC/GraphQL 确保端对端类型安全,能避免很多接口对接的问题。
    imba97
        39
    imba97  
    OP
       1 天前
    @lefer 别骂了别骂了,之前接的兼职 😂
    klzy
        40
    klzy  
       1 天前
    插一句题外话,是不是直接拿 ruoyi 或者其他基于 ruoyi 修改的框架做的系统,因为我对这个操蛋的地方有一点点印象....
    imba97
        41
    imba97  
    OP
       1 天前
    @sgiyy 后面改了,分分钟改掉了
    ruxuan1306
        42
    ruxuan1306  
       1 天前
    赞同二楼,写个`rows || data`兼容就行了,来回 battle 加发帖内耗两三小时就过去了。
    大多数系统活不过一两年,人生那么多重要的事,还是多花时间汇报吹 b 向上管理。
    imba97
        43
    imba97  
    OP
       1 天前
    @ashing 是的,所以我感觉很离谱,分不分页还跟返回的数据结构有关联了
    imba97
        44
    imba97  
    OP
       1 天前
    imba97
        45
    imba97  
    OP
       1 天前
    @ruxuan1306 也没,后面拉了个会,后端分分钟改完了
    imba97
        46
    imba97  
    OP
       1 天前
    @klzy 后端是 JAVA ,应该是 Spring Boot
    imba97
        47
    imba97  
    OP
       1 天前
    @demonzoo 好像是不小心改错了之类的,所以没通知前端,这个倒是可以理解
    metalvest
        48
    metalvest  
       1 天前 via Android
    OP 想的是如果数据结构统一了,至少就可以避免这次前端做无用功的排错。但后端想的是幸好没统一,不然可能很久都发现不了这次误操作。
    imba97
        49
    imba97  
    OP
       1 天前
    @metalvest 但我感觉,反而分页失效了能更直观的看出来,比一个 key 变了更能快速发现
    dayeye2006199
        50
    dayeye2006199  
       1 天前 via Android
    问就是 graphql
    zerovoid
        51
    zerovoid  
       1 天前 via Android
    加个判断的事情,除非有代码洁癖,没有让前端自己去拉数据库增删改查就不错了。
    lijianan
        52
    lijianan  
       1 天前
    https://zod.dev 用起来,数据结构不对直接拦住,UI 降级一下把错误展示出来
    xuanbg
        53
    xuanbg  
       1 天前
    其实 OP 说的是原先不管是数组还是对象,都放在 data 字段。现在后端改成 data 字段只放对象,数组则放到 rows 字段。这种无厘头行为给 OP 带来了困扰,原先写好的获取数组的接口都要相应修改成取 rows 字段才能正确显示数据。

    这不是赛博画蛇添足么? OP 你应该问下后端用 data 返回数组判几年?
    zhaokun
        54
    zhaokun  
       1 天前
    是否启用分页我一般给个参数让前段控制,返回结构是一样的
    lcbp
        55
    lcbp  
       1 天前
    是否分页为什么要换接口,为什么要两种不同的数据方式。后端接口支持传递分页参数(页码、每页数量)不就行了吗?

    {
    code: 200,
    message: '',
    data: 列表数据 Array<item>,
    meta: { pagination: {当前页码、本业数据条数、是否有下一页、记录总数} }
    }
    tabc2tgacd
        56
    tabc2tgacd  
       1 天前
    这里一个关键是:事先有没有做出这样的约定?如果有作出约定,那是前端的锅,如果没作出约定那就是后端的锅。至于是不是合理,反而不重要。
    andytao
        57
    andytao  
       1 天前
    升高维度:请他一根烟 或 一瓶可乐,建议改成一致, 不就双方都很愉快嘛
    a33291
        58
    a33291  
       1 天前
    正好前不久遇到过第三方类似的设计
    作为后端,我觉得这就是后端设计问题,况且统一的数据结构对后端来说也更简单
    laminux29
        59
    laminux29  
       1 天前   ❤️ 5
    看了楼上的评论区,深刻反映出:我国软件水平还非常低,低还普信。

    OP 的考虑是对的,对于专业的软工,正确的做法是,只用一套数据结构,在数据结构内部,通过 pageCount 来判断是否有分页。如果无分页,pageCount 为 1 ,表示只有 1 页数据。如果大于 1 页,表示有分页。

    楼上那些 2 套接口、甚至 rows || data ,全都是瞎搞。
    november
        60
    november  
       1 天前 via iPhone
    有没有改,直接看 git commit 不就有了?
    lscho
        61
    lscho  
       1 天前
    我是后端,这个问题从表面上看肯定是后端的锅,同一个接口出来两种不同结构的数据就是不符合规范的。

    从根源上说你们整个组都有问题,应该先定规范再开发,而不是中间遇到问题再协商。

    即使是遇到问题需要协商,也需要有一个拍板决定的人来决定怎么处理。
    simo
        62
    simo  
       1 天前
    往业务链上游走,先从产品经理开始,一渣到底,折磨死后端
    chairuosen
        63
    chairuosen  
       1 天前
    我的做法:反正我不该,你爱咋咋地,你找谁都没用
    zacard
        64
    zacard  
       1 天前
    改接口定义已经是违反开闭原则了,还不通知前端,首先后端就是理亏了。数据结构合理性上说,不管是否分页,肯定都是包在 data 里面符合业内普遍做法
    imba97
        65
    imba97  
    OP
       1 天前
    @xuanbg 之后后端其实分分钟改好了,我就感觉很离谱
    iOCZS
        66
    iOCZS  
       1 天前
    无脑 list 。。。。
    imba97
        67
    imba97  
    OP
       1 天前
    @lcbp 也不是分页需要换接口,是调用有分页的接口返回的是 rows 。所以这次的情况是后端可能不小心把有分页改成无分页的数据结构,对于前端排查来说看到接口有数据就会过掉,根本注意不到是 rows 还是 data ,后面做的排错都是无用功,这就让我觉得很难受
    imba97
        68
    imba97  
    OP
       1 天前
    @tabc2tgacd 是这样,之前把有列表的接口改成 rows 我虽然感觉很奇怪但也接受了。这次问题是后端可能不小心改错了,把有分页改成无分页数据结构了,所以 rows 变成 data 了。前端这边排错一般看到接口有数据就排查别的了,根本注意不到 key 是不是变了,后面的排错都是无用功浪费时间。如果都统一了至少不会有这个问题,顶多可能是分页功能失效了,这样前端也能更直观的看出来问题
    imba97
        69
    imba97  
    OP
       1 天前
    @november 我这边没后端代码,而且估计是不小心改掉了,前端排错也不会先注意是 key 变了,看到接口有数据就看别的问题了
    vishun
        70
    vishun  
       1 天前
    后端用的 ruoyi 框架,就是这样,主要问题是后端改了没告知前端的问题,定义一个和两个类型没什么区别。
    imba97
        71
    imba97  
    OP
       1 天前
    @vishun 可能误操作改成无分页数据结构了,问题是后端可能也不知道。所以如果数据结构统一,分页改了最多可能影响前端分页功能失效,前端能更直观的发现问题
    digimoon
        72
    digimoon  
       1 天前
    能一样就一样我觉得没啥问题,谁愿意每个螺丝孔都用不同的螺丝
    kakki
        73
    kakki  
       1 天前
    @laminux29 有的接口在查询参数不同的情况下,返回 pageCount 为 1 就是无分页,有无分页部分接口应该直接在概念上定义好,而不是根据敲一棍子看看出什么 shit 来判断。
    JayLin5
        74
    JayLin5  
       1 天前
    理论上来说肯定是一致最好,但是实际开发过程中,看谁强势一点哈哈哈,能叼的过他直接开叼,叼不过默默改前端加个判断,都是草台班子,对于老板来说项目跑起来就行,反正等你离职之后痛苦的是下一位,然后下一位就开始骂祖传代码。
    panbeta
        75
    panbeta  
       1 天前
    服务端刚毕业吗? 这水平做外包都勉强
    november
        76
    november  
       1 天前 via iPhone
    @imba97 其实我意思是,后端说自己没改,直接一起查代码看看。
    当然这种做法容易得罪人,但也高效责任明确。不用双方都口嗨。
    kakki
        77
    kakki  
       1 天前
    @laminux29 我又看了一下上下文,很明显我们讨论的完全不是一个东西~
    我们讲的是“相同实体的有无分页数据接口”,你讲的是”分页接口的有无分页判断“,很明显,这不是一个东西。
    jianghu52
        78
    jianghu52  
       1 天前
    我说头像怎么这么熟悉呢,原来是 B 站的博主啊。加油。
    cuberlzy
        79
    cuberlzy  
       1 天前 via iPhone
    无所谓。争赢了去下家公司还得争
    laminux29
        80
    laminux29  
       1 天前
    @kakki

    我的意思是,一个接口就够了,根本就不需要为了分不分页去搞 2 个或多个接口。
    imba97
        81
    imba97  
    OP
       1 天前
    @JayLin5 确实,最后只能还是叼过
    imba97
        82
    imba97  
    OP
       1 天前
    @november 没有,后端发现改错了,我感觉失误改错了不是什么很大的问题,我是更在意这个返回结构一致性的问题
    imba97
        83
    imba97  
    OP
       1 天前
    @jianghu52 好嘞,感谢 👍
    imba97
        84
    imba97  
    OP
       1 天前
    @cuberlzy 那倒也是,但至少我还是想,不管在哪我自己的开发体验都要尽量高一点的
    jiangzm
        85
    jiangzm  
       1 天前
    分页和列表肯定都要存在不能为了结构相同而直接简单粗暴统一返回结构。要统一的时候不同数据分页接口的结构和不同数据列表接口的结构。

    如果后端是不小心改了原接口的返回结构, 那 100%是后端的锅,哪怕原来的接口不合理是代码逻辑很糟糕也不能随便改。

    如果是新接口前端通用请求预期的结构和后端返回的不一致, 那属于前期沟通和前端自测有问题。

    另外不建议把分页和列表结构放到一个类型定义中,定义 PageData 和 ListData 即可, 通用接口请求方法根据入参(有无分页参数)很容易区别响应类型。
    ooo4
        86
    ooo4  
       23 小时 19 分钟前
    以前我也觉得后端返回的数据结构应该保持一致,直到后面被安排到其他项目组,里面的后端都是公司呆了 10 多年那种,接口写的十分的丑陋,什么拼音啊,额外字段用什么 xxx1 ,xxxx2 ,xxxx3 前端根本用不上,虽然代码很恶心,但管他的,说不定明年你就跑路了
    demonzoo
        87
    demonzoo  
       23 小时 11 分钟前
    @imba97 好像是不小心改错了之类的,所以没通知前端,这个倒是可以理解
    ==============
    听起来似乎完全没有自动化测试的样子,这种真的无语
    wangtian2020
        88
    wangtian2020  
       11 小时 25 分钟前
    关于页面需不需要分页这个问题我已经找到真理了,就是统一只提供一个分页接口。想要不分页? pageSize:9999 了解一下,一个接口按你需要随你掉
    对接后端接口最怕的就是对象结构会变的,这是对后端最基本的要求,接口对象的结构不能变,而且要统一。别信他瞎几把扯,设计混乱的接口能不能用,能用也能跑,代码和人有一个能跑就行,代码可以是屎山不是我接手就没意见。
    不,我也是有意见的,我这个人就是见不得设计的屎的接口。
    直接怼后端,别惯着这种菜逼
    imba97
        89
    imba97  
    OP
       10 小时 52 分钟前
    @ooo4 是个兼职,时间上来说公司这边年底贼忙,已经提了要跑路了
    imba97
        90
    imba97  
    OP
       10 小时 51 分钟前
    @demonzoo 看起来是没有的,虽然前端也没有
    fenglangjuxu
        91
    fenglangjuxu  
       10 小时 49 分钟前
    盲猜后端用的是 ruoyi
    nanpu
        92
    nanpu  
       9 小时 14 分钟前
    ruoyi 分页和不分页返回结构是不一样的,后端改错了
    Yanlongli
        93
    Yanlongli  
       6 小时 51 分钟前
    不管是统一还是不统一其实都无所谓,但是前提要提前沟通,不能直接就换了不通知。
    今天还是 rows ,第二天变成了 data ,第三天变成了 list ,第四天换成 records ,第五天换成 elements, [🐶]
    BG7ZAG
        94
    BG7ZAG  
       4 小时 39 分钟前
    如果是 app 端强类型语言的话,这种动态相应类型直接爆炸
    mark2025
        95
    mark2025  
       22 分钟前
    @wangtian2020 统一用分页的类型,不分页就当是 LIMIT 1 OFFSET 0 的特例嘛。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3222 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 12:17 · PVG 20:17 · LAX 04:17 · JFK 07:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.