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

有没有这样一个 lib,可以帮 js 前端“清理”后台 api 返回的数据结构?

  •  2
     
  •   wxsm ·
    wxsms · 2017-12-20 19:56:39 +08:00 · 6391 次点击
    这是一个创建于 2531 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如说,按照约定后台应该返回这样的一个数据结构:

    {
      a: {
        b: [] // 某数组
      },
      c: '某字符串'
    }
    
    

    但是有时候事与愿违,团队开发者一多,后台往往会返回缺斤少两或者奇怪的东西,导致错误,比如

    {
      a: null,
      c: null
    }
    
    

    或者:

    {
      a: {
        b: null
      }
    }
    
    

    我知道可以通过逐个字段判空来解决,但这太麻烦了,而且一不小心就漏掉了什么地方。有没有一种工具,可以对这样的数据按照约定结构进行补全呢?

    比如:

    • 数组默认为 []
    • 对象默认为 {}
    • 字符串默认为空字符串
    • 数字默认为 0
    50 条回复    2017-12-21 11:43:55 +08:00
    muziyue
        1
    muziyue  
       2017-12-20 20:07:23 +08:00   ❤️ 6
    想法不错,不过遇到这种情况找后端打一架比较管用
    orancho
        2
    orancho  
       2017-12-20 20:10:17 +08:00
    Protobuf 请。
    264768502
        3
    264768502  
       2017-12-20 20:12:13 +08:00 via iPad
    LancerComet
        4
    LancerComet  
       2017-12-20 20:22:46 +08:00   ❤️ 1
    看了上文,实际上如果接口很多业务很个性,为了确保类型安全还是要写很多业务相关的过滤器,目前看来并没有什么特别好的偷懒方法.

    在下所在项目目前的实践是为关键服务的接口写过滤器 + TS Definition,并会在代码审核时检查,说白了就是这个任务一点没省,只不过是平均了罢了.

    期待有更好的偷懒实践.
    wxsm
        5
    wxsm  
    OP
       2017-12-20 20:23:08 +08:00
    @muziyue 打得了现任打不了下一任,自己不做处理总会有被坑的一天。

    @orancho 这个好像是新的数据交换结构,新项目可以考虑,可是现有的基于 JSON 的项目怎么搞?

    @264768502 好像不是我想要的东西。
    crysislinux
        6
    crysislinux  
       2017-12-20 20:26:15 +08:00   ❤️ 3
    json schema 校验,放在后端的出口就好了,不符合 schema 的就直接报错让后端改,不然你补全了有什么用,你补的了代码补不了逻辑。
    orancho
        7
    orancho  
       2017-12-20 20:27:14 +08:00
    @wxsm

    现有项目的话只能靠沟通和管理了,当然你也可以试着迁移一下。
    P.S. 我司自从尝了 protobuf 的甜头之后大部分项目都迁移了过去。
    zjsxwc
        8
    zjsxwc  
       2017-12-20 20:35:18 +08:00
    必须要前后端都有一个约定才能解决楼主问题,不然缺斤少两的情况下,也无法判断出缺的那个字段是补成[]还是{}还是""还是 0
    zjsxwc
        9
    zjsxwc  
       2017-12-20 20:45:11 +08:00   ❤️ 1
    2 个办法:

    1. 类似 protobuf 辅助在代码上统一,*约定*通过编写 protobuf 消息文件来指定, 要改原来的代码

    2. 用中间转发网关,*约定*通过在这个中间网关里通过图形界面配置,我记得有开源的
    maemual
        10
    maemual  
       2017-12-20 20:46:23 +08:00 via Android
    我觉得在后端数据无法通过工具约束的情况下,遇到这种错误的数据直接报错更好一点。否则用默认值,当作正常数据再写回到后端的话,以后坑更大。
    Torpedo
        11
    Torpedo  
       2017-12-20 20:48:17 +08:00   ❤️ 1
    之前的项目就是这样。服务代理了很多接口,接口文档都没有。他们的数据总是不稳定。
    其实我理解这个问题有两点:
    1.不管什么库,按照你说的那么做都要把数据结构描述一遍。
    2.找出不符合的情况不难,那么我一个一个写呢。但是比较大的问题是:这么多字段,每个出问题了都是一个异常处理逻辑。

    基于以上两点,1 明显应该是大家约定的,但是却约定不好。2 一个个写太多。
    我们用了 react,所以比较好的方法是用 react16 的 componentDidCatch,封了一个高阶组件来统一处理页面模块出错。

    本来这问题就是数据问题,哪个数据问题就修复哪个数据就行了。只是前端这里处理,不因为他们的数据问题让整个页面挂掉就可以了
    cenqingbo
        12
    cenqingbo  
       2017-12-20 20:52:49 +08:00
    @crysislinux 作者贴出来的错误的 null 返回也属于正确的 json shema 吧
    Terry05
        13
    Terry05  
       2017-12-20 21:02:28 +08:00
    没啥好偷懒的,一个个节点去判断
    will0404
        14
    will0404  
       2017-12-20 21:09:47 +08:00 via iPhone
    这绝对是后端的锅啊,为什么要前端做?在 api 输出的地方做类型检查就好了,前端加个 lib 增加多少流量考虑过吗
    wxsm
        15
    wxsm  
    OP
       2017-12-20 21:10:09 +08:00 via iPhone
    @zjsxwc 你说的这种“网关”其实不切实际。这样一来架构会变得极其脆弱。

    @maemual 主要是用来显示的这一块,不往回发。一报错测试马上就找到前端来了,各种背锅。

    @Torpedo 你这个办法看起来不错,我这边也是 RN,明天试一下。谢谢。
    wxsm
        16
    wxsm  
    OP
       2017-12-20 21:13:46 +08:00 via iPhone
    @will0404 组织已经决定了,这个锅就 tm 前端来背。
    sensui7
        17
    sensui7  
       2017-12-20 21:35:31 +08:00   ❤️ 4
    参考这个视频:
    jzhang
        18
    jzhang  
       2017-12-20 21:43:24 +08:00   ❤️ 1
    isbase
        19
    isbase  
       2017-12-20 21:53:51 +08:00
    @Torpedo 我觉得如果是后端数据的问题,那就该正常抛出错误让页面挂掉,否则你 catch 了错误继续运行下去可能会导致更严重的问题

    @wxsm 平时写代码的时候可以多用 ES6 的函数参数默认值
    wanganjun
        20
    wanganjun  
       2017-12-20 21:53:52 +08:00 via iPhone
    为啥没人说 graphql
    janxin
        21
    janxin  
       2017-12-20 22:08:36 +08:00
    @wanganjun 因为 graphql 没有什么收益,除了前端偷懒以外
    kaneg
        22
    kaneg  
       2017-12-20 22:09:37 +08:00 via iPhone
    把后端返回的 json 合并到定义的默认 json,是不是就得到楼主想要的结果了?
    aegisho
        23
    aegisho  
       2017-12-20 22:14:40 +08:00 via Android
    1.明确规范,出 bug 算到后端的责任
    2.老老实实写防御性代码
    3.考虑类似 json schema 校验补全
    4. 我能(要)打十个
    wxsm
        24
    wxsm  
    OP
       2017-12-20 22:17:34 +08:00 via iPhone
    @jzhang 看了一圈文档,貌似没有发现对缺失值的处理办法?

    @isbase 默认值只能解决很小一部分的问题。通常数据都会有深层次的结构。

    @kaneg 同上。
    vinceguo
        25
    vinceguo  
       2017-12-20 22:48:23 +08:00 via Android
    楼上有人提到 protobuf,那我就顺便说一下 thrift 吧。类似的东西
    RorschachZZZ
        26
    RorschachZZZ  
       2017-12-21 00:06:53 +08:00
    这就是参数规范化的重要性。
    Obelly
        27
    Obelly  
       2017-12-21 01:44:26 +08:00
    一种“天才”的解决方案,将所有非数字全部格式化成字符串,要处理数据再另行处理字符串文本内容……
    Mutoo
        28
    Mutoo  
       2017-12-21 06:22:07 +08:00
    1) json schema
    2) lodash _.get(obj, path, default) 方法
    https://lodash.com/docs/4.17.4#get

    var object = { 'a': [{ 'b': { 'c': 3 } }] };

    _.get(object, 'a[0].b.c');
    // => 3

    _.get(object, ['a', '0', 'b', 'c']);
    // => 3

    _.get(object, 'a.b.c', 'default');
    // => 'default'
    crysislinux
        29
    crysislinux  
       2017-12-21 07:12:13 +08:00
    @cenqingbo 不全是,当然 schema 也不能保证逻辑正确,但是能保证该在的 fields 都在,类型都对
    wxsm
        30
    wxsm  
    OP
       2017-12-21 08:45:28 +08:00 via iPhone
    @Mutoo 这种实际上就是逐个字段判断了。而且这个 defalt 有局限性,处理的只是 key 不存在的情况。万一存在而且是 null,那还是会有问题。还得再加判断。麻烦得很。
    wotemelon
        31
    wotemelon  
       2017-12-21 09:02:41 +08:00   ❤️ 1
    bfbd
        32
    bfbd  
       2017-12-21 09:08:34 +08:00
    Object.assign(retData, defaultData)
    bfbd
        33
    bfbd  
       2017-12-21 09:09:55 +08:00
    写反了,应该是:newData = Object.assign({...defaultData}, retData)
    vghdjgh
        34
    vghdjgh  
       2017-12-21 09:23:57 +08:00 via Android
    这种情况的解决方案就是接口文档中也提供一份语言无关的 protobuf 或 json schema 文件,然后收到数据时做验证
    如果用 typescript,我用 https://github.com/plantain-00/types-as-schema 通过 types 生成 json schema 或 protobuf 文件
    mougua
        35
    mougua  
       2017-12-21 09:34:11 +08:00
    这种情况,我一般是买把菜刀放桌子上,然后叫后端同学来谈谈接口~~~~
    YMB
        36
    YMB  
       2017-12-21 09:35:17 +08:00
    我觉得开发 API,第一件事就是定义接口规范,第二是授权机制。
    接口规范可以用一个类封装一下,授权机制可以用中间件过滤一下。
    然后写业务逻辑,基本没什么问题。
    th00000
        37
    th00000  
       2017-12-21 09:39:51 +08:00
    我完全同意一楼的看法 出现这种情况直接把后端打残比较好
    evolify
        38
    evolify  
       2017-12-21 09:39:57 +08:00
    和楼主一样的情况。而且更离谱的是,对于为空 l 的字段,他们直接 ignore 了,说是什么发的数据少一点快一点,简直是扯淡的优化。之前好好的,这么一搞,我前端一堆 undefined. 现在我的做法是在接收后台数据时,手动重新赋值,所有字段都用我习惯的命名方式,不然他后台又一改字段或者说两个地方字段名不一致,那就 GG 了。
    justfindu
        39
    justfindu  
       2017-12-21 09:41:32 +08:00
    这个完全不能做呀, 智能化了解你的接口数据, 比如你的示例 给的 b:null, 那我应该给 b 一个{} 还是一个[] 还是'' . 你会说你可以通过配置来确定某个接口给的数据是什么, 那为什么不直接跟后端沟通? 这才是正确的出路啊...不规范的接口以后都是痛. 难道你 APP 也要一个筛选?
    wxsm
        40
    wxsm  
    OP
       2017-12-21 09:42:52 +08:00
    @wotemelon 这个有这么点意思,好像是我想要的东西。谢谢!
    wxsm
        41
    wxsm  
    OP
       2017-12-21 09:48:23 +08:00
    @justfindu 因为前端对数据的类型是有“预期”的(按照约定)。比如说正常来说数组都是用来遍历的,但是后台就返回了个 null,导致遍历失败报错。如果我按照“预期”把它变成一个 [],那不就解决了。团队开发者一多,沟通成本很高,反正我提过很多次了,根本没人鸟我。
    li746224
        42
    li746224  
       2017-12-21 09:50:52 +08:00
    graphql 吧,虽然觉得前端收益大,后端搞起来麻烦
    v2chou
        43
    v2chou  
       2017-12-21 09:51:33 +08:00
    我们后台就是这样
    leemove
        44
    leemove  
       2017-12-21 10:05:16 +08:00
    哎呀 现在每一个请求我都会 catch.最要命的的是超时.
    justfindu
        45
    justfindu  
       2017-12-21 11:01:33 +08:00
    @wxsm 所以我说你要通过配置预期来格式化每一个接口, 接口数据一多, 你就死了. 虽然我是后端, 但是这锅明显要甩给后端. 你就不管, 只要不符合格式, catch 到错误, 你就提示数据无法获取 哈哈哈哈
    ChristopherWu
        46
    ChristopherWu  
       2017-12-21 11:27:18 +08:00
    这种一般后端做,如上面同学说的 json schema,不但验证 request,给前端 response 也验证了。
    后端不上只能打一架了
    yuxuan
        47
    yuxuan  
       2017-12-21 11:29:20 +08:00
    明显后端的锅 楼主要强势一些 加 lib 是在牺牲前端性能来做
    kenshinhu
        48
    kenshinhu  
       2017-12-21 11:31:02 +08:00
    有责任的后端都会把这个解决的
    denano
        49
    denano  
       2017-12-21 11:41:12 +08:00
    和后端定好数据结构,给出 api 文档当然是最好的了,还有自己前端写个函数判断下返回值结构咯
    paradoxs
        50
    paradoxs  
       2017-12-21 11:43:55 +08:00
    我们公司的话,大概 这个样子
    {
    result: 000000 成功 999999 失败 22222 某某错误
    msg:
    data :
    }
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2895 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 12:16 · PVG 20:16 · LAX 04:16 · JFK 07:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.