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

可能是另一场圣战:后端返回的 JSON 的值是只要 String 类型呢,还是各种类型都包括呢?

  •  
  •   winiex · 2018-05-19 15:21:21 +08:00 · 18943 次点击
    这是一个创建于 2141 天前的主题,其中的信息可能已经有所发展或是发生改变。

    工作中和不同的客户端开发者合作过,有的要求返回的 JSON 统一只包含 String 类型:

    { a: "THYM", b: "107", c: "false" }

    而有的则要求数据要表达自己的类型:

    { a: "THYM", b: 107, c: false }

    我个人是支持第二种写法的,因为不用再写一堆转 String 和转回类型的代码。大家团队都选择何种方式呢?又是出于何种原因与理由呢?

    161 条回复    2018-05-22 22:11:10 +08:00
    1  2  
    huclengyue
        1
    huclengyue  
       2018-05-19 15:22:56 +08:00 via Android
    第一种, 并且 boolean 用 1 0 表示
    roy2220
        2
    roy2220  
       2018-05-19 15:23:35 +08:00 via Android   ❤️ 5
    我选择 protobuf
    forestyuan
        3
    forestyuan  
       2018-05-19 15:25:56 +08:00
    第二种更合理
    lolizeppelin
        4
    lolizeppelin  
       2018-05-19 15:29:17 +08:00 via Android   ❤️ 1
    按标准来 都有校验 第一种明显不标准
    wxsm
        5
    wxsm  
       2018-05-19 15:29:32 +08:00 via iPhone
    敢问第一种的意义?
    airyland
        6
    airyland  
       2018-05-19 15:29:46 +08:00   ❤️ 2
    当然是二,该是数字的应该是数字,该是布尔的就该是布尔。第一种写法的可能还会要求你把原该是数字、布尔用字符传参 post。如果前端使用了 Vue, React 组件,那么意味着渲染前你要转换一次,提交前要重新转换一次,实在是浪费不必要的时间。
    Death
        7
    Death  
       2018-05-19 15:37:27 +08:00 via Android   ❤️ 1
    第二种,json 本身就是包含了类型的。这样用 json schema 检验起来也方便。
    janus77
        8
    janus77  
       2018-05-19 15:37:29 +08:00
    这是不是 php 啊
    sagaxu
        9
    sagaxu  
       2018-05-19 15:37:48 +08:00 via Android   ❤️ 47
    这还能有争议?第一种是 sb 做法。
    duan602728596
        10
    duan602728596  
       2018-05-19 15:38:02 +08:00 via iPhone
    都用字符串表示,那还定啥标准?
    shihira
        11
    shihira  
       2018-05-19 15:40:52 +08:00
    不太能理解第一种欸。
    winiex
        12
    winiex  
    OP
       2018-05-19 15:42:54 +08:00
    @huclengyue
    能说一下这样做的理由吗?我有好几个前同事和你的做法是一样的。

    @lolizeppelin
    @airyland
    @Death
    @duan602728596
    我和各位的想法是一样的。但是基本上总有客户端开发者要求做成第一种。一直不是很清楚其中的缘由。
    DavidNineRoc
        13
    DavidNineRoc  
       2018-05-19 15:47:15 +08:00 via Android
    @janus77 日常黑?
    monsterxx03
        14
    monsterxx03  
       2018-05-19 15:51:10 +08:00 via iPhone
    js 不能处理大整数,有时为了统一,所以会有用第一种的
    luoyou1014
        15
    luoyou1014  
       2018-05-19 15:55:19 +08:00   ❤️ 9
    第二种是理论最优,但实际上跑过大型的复杂的系统之后,整个团队会倾向于第一种写法( bool 采用 0 和 1 表示)。

    具体原因是客户端数据类型错误的时候会导致应用直接闪退,虽然明确类型是最优解决方案,但是客户端无法确定服务器端会不会返回错误的类型,到时候客户端就闪了,对于 boss 而言,出现闪退这种严重的问题,竟然只是因为类型错误导致的,团队里面都很难承担这种压力,最终开发在实际应用中会尽量将除 id 之外的字段全部转成 string 来解决类型错误的问题。
    airyland
        16
    airyland  
       2018-05-19 15:56:53 +08:00   ❤️ 1
    @luoyou1014 这看起来是代码没有 review 团队没有规范导致的吧。
    stabc
        17
    stabc  
       2018-05-19 16:00:25 +08:00   ❤️ 1
    你要是纠结 "107" 和 107 我能够理解。但是你纠结"false"和 false,你逗我玩呢?
    imnpc
        18
    imnpc  
       2018-05-19 16:01:25 +08:00
    对接几个 java 的支付接口 要求必须第一种
    imn1
        19
    imn1  
       2018-05-19 16:01:42 +08:00   ❤️ 1
    如果要对 json 做预处理的,会喜欢第一种
    因为「易入难出」原则,模块并不清楚 json 的结构和数据类型,所以要判断一次再处理,string 则判断的过程简化,且能「预见」处理结果,如果浮点数 1.01 ,是不能确定处理结果会否变成 1.0099999999999998 的
    尤其是用同一个模块预处理多个不同来源的 json 时,更希望类型单一

    而直接使用 json 的,则喜欢第二种
    isbase
        20
    isbase  
       2018-05-19 16:06:08 +08:00
    第一种完全是扯淡,这种奇葩需求让他自己加中间层去搞
    southsala
        21
    southsala  
       2018-05-19 16:17:21 +08:00
    Json 也是有标准的好吧。。。 第一种这个不算 Json 了吧,算变种
    learnshare
        22
    learnshare  
       2018-05-19 16:19:29 +08:00
    第一种是不行的,绝对不行
    incompatible
        23
    incompatible  
       2018-05-19 16:20:22 +08:00   ❤️ 2
    @luoyou1014 具体原因是“客户端数据类型错误的时候会导致应用直接闪退”,那就解决这个原因啊。你们客户端工程师连异常处理都不懂的?
    Zzdex
        24
    Zzdex  
       2018-05-19 16:23:04 +08:00 via iPhone
    这还站什么?返回第一个直接打死
    VeryCB
        25
    VeryCB  
       2018-05-19 16:42:20 +08:00 via iPhone
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER

    JS 有最大安全整数的限制,所以当有使用大整数的场景下用 string 来表示。不过这需要开发者提前了解需求中是否会出现超过最大安全整数的场景,需求是否合理以及是否可以规避。一般来说用到的可能性很小。

    其他的用第一种的理由应该都是偷懒吧,甚至可能更麻烦一些。
    loveyu
        26
    loveyu  
       2018-05-19 17:15:33 +08:00 via Android
    就是客户端偷懒,问过了,说实现复杂
    applehater
        27
    applehater  
       2018-05-19 17:21:47 +08:00
    有种叫 BSON
    zhujinliang
        28
    zhujinliang  
       2018-05-19 17:39:11 +08:00 via iPhone
    第一种,一个 if (obj.c) { ... } 就等着出诡异的 bug 吧
    dacapoday
        29
    dacapoday  
       2018-05-19 17:50:56 +08:00
    和楼主有同样的疑惑(还有 bool 用 0,1 表示),经常出现在 java 程序员里,应该不是不理解(甚至不知道?)JSON 规范。
    只用 string 便于存储到数据库里,建表和编写简单。
    HangoX
        30
    HangoX  
       2018-05-19 17:51:35 +08:00
    @luoyou1014 别傻了,客户端从开发开始都是信不过服务器的,所有解析的地方都是对 错误做了 catch 处理,绝对不会崩溃的。
    scriptB0y
        31
    scriptB0y  
       2018-05-19 17:54:01 +08:00
    提出第一种要求的是银行吧,我还见过客户端将服务器 SSL 证书验证写死在代码里,导致人家服务方不方便更换 SSL 证书的。
    kslr
        32
    kslr  
       2018-05-19 18:33:59 +08:00 via Android
    直接 true 会有问题 中间层都是做了转换的 0 or 1
    ikaros
        33
    ikaros  
       2018-05-19 18:37:46 +08:00
    第一种让别人怎么解?
    boywang004
        34
    boywang004  
       2018-05-19 18:54:46 +08:00
    万事不能一棍子打死!我仔细想了下都是 string 的方案……真 tm sb ……
    janxin
        35
    janxin  
       2018-05-19 19:09:35 +08:00 via iPad
    第一种方案很简单的思路,假如你在一个管控非常差的团队,又要求产品很稳定,但是哪个产品和领导每天想着要更新迭代加功能。程序员质量又没有那么好,甚至有些文档都没有。一些时候你调用别人的接口数据直接返回了也没处理。某天,有个傻逼,没注意数据类型把类型改了,你发现你的接口客户都不能用了…
    Eoss
        36
    Eoss  
       2018-05-19 19:09:53 +08:00
    @huclengyue

    那些使用第一种,bool 使用 0,1 表示的,怎么让前端判断 false,true ?
    Boolean(Number('0')) ???
    zythum
        37
    zythum  
       2018-05-19 19:18:43 +08:00
    第一种并不是完全不对的,其实避免了一些问题。

    比如,有些语言是强类型,有些事弱类型,有些 Number 有 Int,BigInt, Float 的区别有些没有。所以传数字有时候是有歧义的。这是不用语言间天然的,比如 js, 数字大于 32 为带符号整型就傻逼了,但是 JSON 官方貌似并没有规范这个。

    所以第一种并不一定是 SB,拍脑袋定的,只是他们或许是被坑过的同学。
    ZiLong
        38
    ZiLong  
       2018-05-19 19:20:28 +08:00
    @imn1 对于你提到的预处理不甚理解?就是浮点数精度问题和大整数问题?是否可以这样制定规则,浮点数和大整数需要用 string 类型,其他仍然用原类型就不出出问题了?如果要出问题,可以举个例子么
    momocraft
        39
    momocraft  
       2018-05-19 19:27:35 +08:00
    在第一种人写的系统中使用字符串 "null" 可能会导致一些有趣的问题
    chinvo
        40
    chinvo  
       2018-05-19 19:30:19 +08:00 via iPhone
    @zythum #37 无脑用 string 也不对,比如 boolean, null
    imn1
        41
    imn1  
       2018-05-19 19:39:22 +08:00
    @ZiLong
    例如一个项目,有 ABC 多个模块,它们之间都是通过一种二维数组传递数据的
    这时,因为需要,从外部获取一个源数据,而它是由提供方决定格式的(例如 json ),项目组无法决定其格式或类型
    这时就需要用一个 D 模块处理,转换为二维数组,交给 ABC 使用
    正因为数据源是外部,往往 D 模块里面要加容错代码,如果类型复杂,容错和转换工作就多很多,只是 string 就简单了

    如果数据源头有多个,可变(例如合作方变更),预处理就很必要了,没理由改变原来项目的 ABC 的

    这种情况以前见得多了,曾见过一个糟糕的项目,合作方改了数据格式,项目就要重写……
    hyyou2010
        42
    hyyou2010  
       2018-05-19 20:00:02 +08:00
    差异可能在于两种方式在客户端的出错处理位置不同,难度不同

    考虑到语言特性,数值边界,那么 api 接口最好很直白,很傻,并排除任何语言特性的影响

    过去的项目是 2,但在数据类型上趟过太多痛苦的坑,考虑以后试试 1
    Him
        43
    Him  
       2018-05-19 20:13:46 +08:00
    @janxin 不走测试环境测试直接把修改上线,这样的团队连基本的流程都没有了……
    hyyou2010
        44
    hyyou2010  
       2018-05-19 20:15:56 +08:00   ❤️ 1
    说几个接口的坑,不一定对,供参考:
    1、数组里面必定同类型,不然强类型语言处理起来麻烦
    2、不要用 bool,而用整型 0、1,不然不好扩展
    3、不要有 null 或别的空类型定义,整型的话用-1 表示没有,字符串用“”或其他特别串表示没有
    GreenVine
        45
    GreenVine  
       2018-05-19 20:17:28 +08:00 via iPhone
    @scriptB0y 看上去是 Certificate pinning 防止中间人的
    iwtbauh
        46
    iwtbauh  
       2018-05-19 20:39:42 +08:00 via Android
    @scriptB0y 这个和话题关系不大啊,写死可能带来巨大安全好处。公钥钉扎( public key pinning )了解一下。Google 就曾经将自己域名的证书写死在 chrome 里,也是因为这种操作,某个 CA 的二级私自签发 google 域的证书(哪家不用我说了吧,就是这事之后被 Mozilla 和 Google 拉黑的那家),但 chrome 避免了被中间人攻击。同时使用 chrome 的用户自动将事件报告 Google,并公之于众。

    钉扎是出于安全方面的考虑,但的却会带来你说的那种不易换证书的问题,但这要看怎么权衡了。
    Hardrain
        47
    Hardrain  
       2018-05-19 20:46:07 +08:00
    boolean 也要变成 str?

    有的语言似乎不能直接把 str 转回 boolean ……
    prolic
        48
    prolic  
       2018-05-19 20:46:52 +08:00
    一直在用第一种,流程中备不住哪个用 php 的写的菜一点,就 int string 混用了,还不如从头到尾强转 string 还能统一一下
    Axurez
        49
    Axurez  
       2018-05-19 20:50:02 +08:00
    居然还有选 1 的,今天也是长见识了。
    hxy91819
        50
    hxy91819  
       2018-05-19 20:51:46 +08:00
    我们团队是用第二种方案,甚至服务端有些不合规范的字段,客户端会要求按类型规范整理。
    Axurez
        51
    Axurez  
       2018-05-19 20:57:19 +08:00
    敢问选 1 了之后,如果字段是一个对象怎么办?比如

    ```
    { "a": { "b": "107", "c": "false" } }
    ```

    按照某些理论,就应该把对象转字符串,因为对象不靠谱:

    ```
    { "a": "{ \"b\": \"107\", \"c\": \"false\" }" }
    ```

    那么问题来了,你这个根对象不也是个对象?难到你也要包成字符串?


    ```
    "{ \"a\": \"{ \\\"b\\\": \\\"107\\\", \\\"c\\\": \\\"false\\\" }\" }"
    ```

    ???那你为啥还要用 JSON 呢?为啥不自己发明一种格式?
    peterpark
        52
    peterpark  
       2018-05-19 21:02:16 +08:00
    偶遇聂帅^_^
    huclengyue
        53
    huclengyue  
       2018-05-19 21:09:24 +08:00 via Android
    @Death @Death @airyland @wxsm @winiex 你去问问 iOS 开发者就知道了,
    huclengyue
        54
    huclengyue  
       2018-05-19 21:10:56 +08:00 via Android
    @huclengyue 当然如果只是前端 js 的话,第二种效率更高
    huclengyue
        55
    huclengyue  
       2018-05-19 21:12:37 +08:00 via Android
    @airyland 并不是。。。
    huclengyue
        56
    huclengyue  
       2018-05-19 21:14:01 +08:00 via Android
    @isbase 你开发和 android 或者 iOS 应用试试,就知道为什么会是第一种了
    hyyou2010
        57
    hyyou2010  
       2018-05-19 21:15:57 +08:00
    @Axurez

    我的观点是,接口定义上不能有对象这个概念,接口必须是字面的,plain 的。
    我前面写了点个人坑,其中不要 null 或空定义就是针对“对象”的。
    huclengyue
        58
    huclengyue  
       2018-05-19 21:16:42 +08:00 via Android
    @Eoss 那你让 iOS 怎么判断 true false ?? iOS 是 yes no
    huclengyue
        59
    huclengyue  
       2018-05-19 21:21:53 +08:00 via Android
    @Axurez 所以为什么要在接口中传递对象?
    xiaottt
        60
    xiaottt  
       2018-05-19 21:26:03 +08:00 via iPhone
    反正我们合作过的 partner 的文档,都是要求第一种
    Axurez
        61
    Axurez  
       2018-05-19 21:30:41 +08:00
    @hyyou2010 @huclengyue 没有对象可以,可是我说了啊,这个东西本身就是一个对象啊……
    Axurez
        62
    Axurez  
       2018-05-19 21:31:03 +08:00
    @hyyou2010 但你还是不能排除后端直接扔一个 null 过来的情况?
    lxian2
        63
    lxian2  
       2018-05-19 21:32:34 +08:00
    huclengyue
        64
    huclengyue  
       2018-05-19 21:33:06 +08:00 via Android
    @Axurez 所以我们做客户端的很辛苦吧。。不仅判断 null,还要判断"null"😄
    barbery
        65
    barbery  
       2018-05-19 21:35:10 +08:00
    方式二有个坑,就是 bigint 的时候会前端 js 获取值会溢出,后端要生成 string 的格式才行
    hyyou2010
        66
    hyyou2010  
       2018-05-19 21:47:06 +08:00
    @Axurez

    是的,后台扔一个 null 之类过来客户端这边很难处理。从编程上说客户端也是能处理的,但麻烦,隐患无穷,绝对不要选择,要考虑:
    1、换个后台又会发怎样的数据对象过来?
    2、客户端换人之后他还了解这里面的坑不?
    3、加班到很晚脑袋发晕时哪个不容易出错?

    我在多个项目之后的总结就是,只能是整数或字符串,不要布尔和 null 对象,数组内类型统一,等等。
    本主题的 1 是比我更绝对的做法,我暂时不能判断得失。
    janxin
        67
    janxin  
       2018-05-19 21:49:22 +08:00
    @huclengyue SwiftyJSON 之类的库了解一下?
    bobuick
        68
    bobuick  
       2018-05-19 21:51:24 +08:00
    明明人家 JSON 有表达 bool, int 的能力,硬是都 string 不是脑残么
    kslr
        69
    kslr  
       2018-05-19 22:06:54 +08:00 via Android
    @bobuick 这不是脑残,多语言混用会出很多问题,这是经验。bool 用数字 null 变空白
    Mitt
        70
    Mitt  
       2018-05-19 22:23:18 +08:00 via iPhone
    @kslr 从经验上来看,应该是写的人技术不行
    kslr
        71
    kslr  
       2018-05-19 22:26:55 +08:00
    @Mitt #70 所以发布一个行政规则解决这个问题?
    icyalala
        72
    icyalala  
       2018-05-19 22:36:47 +08:00
    @huclengyue
    iOS 那么多 JSON 处理的库,很多都有自动类型转换的功能
    要是 iOS 因为 JSON 传参崩溃或者类型对不上,那只能说这个开发者水平太差
    lamCJ
        73
    lamCJ  
       2018-05-19 22:44:37 +08:00 via iPhone
    前端:后端真*懒 数据库 null 都 tm 直接返回 劳资 iOS 遇到 null 会闪退不懂吗

    后端:客户端真*菜 自己代码类型安全都保证不了 我接口文档返回参数有哪些情况都说那么明白了 还教育我数据库设计不能用 null ?

    其实从谁的角度看都似挺有道理的 但每个角度的问题都有相应的解决办法 这种问题本身也是团队合作和技术管理的问题
    zabida
        74
    zabida  
       2018-05-19 22:54:20 +08:00
    不懂第一种的意义何在
    klesh
        75
    klesh  
       2018-05-19 23:00:48 +08:00
    如果对于具体场景而言,需要的数据表示已经超出了 JSON 的表达能力,比如说 BigInt 这种,与其用所谓的第一种,何不考虑下其他的格式?比如 YAML ?还可以流式按行处理,岂不美哉。
    congeec
        76
    congeec  
       2018-05-19 23:07:07 +08:00 via iPhone
    @winiex 如果 json 数据要放到 ui 里展示出来,都用 string 就方便了,但这也是伪需求啊,只有 C 语言级别的才需要把所有数据都转换成 string 类型。

    如果需要取里面的值做计算,直接一句 MMP 甩他脸上。
    james2013
        77
    james2013  
       2018-05-19 23:09:10 +08:00   ❤️ 2
    当然是第二种好用,本人开发过 Android 应用软件和 Java 后台.以下只是个人看法

    @huclengyue json 本来就是一个对象,在 js 里可以直接用.在 Android,都不敢想象现在谁还去手写 json 解析对象?数据又不少,里面嵌了好几层对象,有的接口像订单详情字段特多,手写会崩溃的.早就用 GsonFormat 将接口结果进行自动解析,后台搞成全 string 的,我都要吐血了.

    @hyyou2010 至于第二种方法,说后台扔一个 null 值给客户端不好处理,我不这么认为.
    楼层中有人说的好,还有一个问题,比如人家把个人资料里描述改成字符串,返回是这样{desc:"null"},用第一种方法,我觉得不好处理.这个是代表该字段没有值还是说"null",歧义很大.第二种的话,就简单了,该字段是{desc:null}或者根本没有返回,说明该字段没有值,如果是{desc:"null"},那说明这是用户设置的.总不可能把客户输入的自动删除掉吧?刚才我试了微信签名,可以单独设置 null.

    对于后台返回的数据,是先通过 json 解析工具自动转成对象的.传 null 过来很正常,本来有的内部对象 /字段是 null,因为该对象 /字段本来就没有数据,在展示的时候,也会先验证.
    比如是对象,验证是否为 null;如果是集合,还需验证集合大小大于 0,要不然,一堆空指针报错,因为同一个接口有的地方是有数据,有的没有.
    列举的 3 个问题,这个跟 json 格式没有关系呀.
    1,2 这种是交接和沟通问题,开发新接口,客户端需要把数据正常显示在 app 上,后台返回错误的格式 /数据也常见,叫后台重新发布,因为项目是采用统一格式返回的.比如{retCode:1,message:"xxx",result:{...}},改了的话很不好.如果是已发布的代码,后台还敢修改接口字段类型和名称,已上线版本容易出大问题的.一般这种是加版本号,而不是在原来版本修改.
    3.的话,我也是承认的,加班疲惫时总会有出错的时候,做第一个也会的.
    missdeer
        78
    missdeer  
       2018-05-19 23:10:46 +08:00 via Android   ❤️ 2
    这就是劣币驱逐良币的过程。最开始一个懒汉或者菜鸟用了第一种,导致其他不那么懒或不那么菜的人只能妥协,慢慢的这个问题现象就范围越来越广了。
    qdwang
        79
    qdwang  
       2018-05-19 23:18:35 +08:00 via iPhone
    需要 json 就用第二种,除非业务有大整数。不用第二种,干嘛还用 json ?自定义二进制格式好了,还省空间
    huclengyue
        80
    huclengyue  
       2018-05-19 23:31:56 +08:00 via Android
    @james2013 你试试动态语言的后端,php python 这种的,java 后端对安卓当然是没问题的,如果各户端是 iOS,怎么办呢? boolean 怎么传
    huclengyue
        81
    huclengyue  
       2018-05-19 23:35:51 +08:00 via Android
    @janxin 以前 oc 时代就这样,我是做安卓的我自己当然是喜欢第二种了,因为 java 各种解析库很完美了,但是有时候遇到 php nodes 等这种弱类型的后端,穿个 int 过来,可能其实是 long。。所以为了稳定减少 bug 还是 string 好一些
    FrailLove
        82
    FrailLove  
       2018-05-19 23:36:43 +08:00
    各种语言都有现成的库 轮子也没要你造 调调库都嫌麻烦了
    huclengyue
        83
    huclengyue  
       2018-05-19 23:37:12 +08:00 via Android
    @missdeer 并不是这个原因,如果是懒汉更喜欢第二种吧,有时候弱类型语言对接强类型语言,第二种很容易出问题。
    luoyou1014
        84
    luoyou1014  
       2018-05-19 23:38:55 +08:00
    @HangoX
    @incompatible

    这类问题不可能完全解决,总归会有漏掉的地方,如果是一次性开发完就不在更新的产品,自然是把所有出问题的地方都解决了即可。

    但是在大型的不断集成新功能的产品,app 有了十几个版本,每个版本的接口都会一直运行,老版本的接口在当时的需求设计下是没有问题的,但是后续需求变动,导致老版的接口出现异常,然后 app 就会出现闪退的情况。还有团队里面会有快速的需求迭代,以及临时的 bug 修复提交代码到线上,这些都有可能造成异常问题。

    代码 review 解决的还是一个有序的问题,但实际情况下不会有时间给每个接口做足够的检查,有 review 的时间还不如让开发自己写接口测试。大型项目里面还存在大量接口转发的问题,例如我的功能里面部分页面已经有其他人现成的接口写好了,我不过是调用对方生成好的数据返回给客户端,这种情况下,天知道对方的代码有没有类型错误的问题,最简单的方案就是直接全部转成 string 来解决。

    最终大家偏向全部 string 方案的原因还是类型错误的这个问题太低级了,但是又很难杜绝,但是出现的闪退问题却又是测试里面被认定为最严重类型的问题,多搞几次这类错误,团队里面谁都扛不住压力,大家只能放弃理论最优方案,转而使用比较 dirty 的方案。
    huclengyue
        85
    huclengyue  
       2018-05-19 23:40:18 +08:00 via Android
    @james2013 还有就目前遇到的问题,php 的 int,有时候对应的其实是 java 的 long,用 gsonformat 解析出来是 int 虽然不会报错,但是数据其实是错的。
    wintercoder
        86
    wintercoder  
       2018-05-19 23:40:38 +08:00
    你们的重点是不是歪了?怎么都讨论 false 和 0 的问题了,0 和 1 替代 true/false 应该没什么人反对吧。说回类型吧,107 和"107" 其实我是懒得处理的,数据库查出来是啥就是啥
    sagaxu
        87
    sagaxu  
       2018-05-19 23:41:38 +08:00 via Android
    @huclengyue 我司 app ios 和安卓都有,后端基本都是 php,新来的员工才会犯这种返回值类型错误,而且这类 bug 都消灭在联调阶段了,连测试阶段都到不了。
    huclengyue
        88
    huclengyue  
       2018-05-19 23:43:40 +08:00 via Android
    @sagaxu 这个问题是可以解决,但是直接传 string 能直接避免这个问题
    cloverstd
        89
    cloverstd  
       2018-05-19 23:48:58 +08:00
    你们不知道 JS 里面最大只能是 i53 吗
    rbe
        90
    rbe  
       2018-05-19 23:52:12 +08:00
    目前团队约定在用的就是类似第一种,不过很多问题的处理不像上面的某些说法理解的那样。

    1. 对 Object,不是直接序列化成为一个字符串,而是继续保留嵌套层级结构,只是处理 数字、bool 类型;
    2. 对于 null 值,必传字段加默认值,非必传字段不传;
    3. 对于 bool 值,很多时候很多字段你是并不能那么确定他一定是非真既假的,举例如你要做一个是否收货的列表,最开始需求不明确快糙猛写成了 `已收货 / 待收货`,你用 bool 值 `isDelivered` 来表示。后来要你加 `全部 / 待付款 / 待评价` 这些状态岂不是要懵逼,所以用 0, 1, 表示是比较保险的;
    4. 对于数字型,就是前面有人提到的,假设后端是动态语言,谁也不能保证代码多了以后,返给前端的接口一定是 int / float / double 区分开的。返回一个 1.0, 客户端写的是 equals(int 1), 就会闪退

    这是我和我们客户端沟通的一些结果,一切都是为了降低客户端的闪退率,毕竟他们的代码发布出去了就没法调整了,而有时候你很难去避免一些错误。

    有什么不对或者说的不好的地方,欢迎继续讨论
    flyingghost
        91
    flyingghost  
       2018-05-20 00:07:29 +08:00   ❤️ 8
    1,不谈 json,绝大部分持久化协议都有类型系统。为什么?可能这些协议设计者规范制定者都是傻子吧!
    2,json 大数字导致 js 解析失败的问题,是怪 json ?我扔个 20 位的字符串你 js 真的就能按 long 处理了吗?我扔个 2000 位的呢?我扔个 10^20 的大数字字符串把你内存撑爆了你是不是还是怪 json ?冤有头债有主,https://www.npmjs.com/package/long 了解一下。要搞科学计算的,请自己实现大数字的解析和计算。别死抓着系统 json 解析库不放,却怪字段类型。
    3,类型错误导致异常的同学,硬生生通过消灭错误的根源解决了错误。你们真厉害,跟 zf 一个处理思路。那值错误问题呢?想个办法也消灭掉?参数个数问题呢?变长参数嘛!参数顺序问题呢?调用时用字典传参写明 key/value 对嘛。参数名拼写问题呢?我编不下去了。。。不过我想聪明人应该能解决,办法总比问题多嘛!

    ——以上是恶搞,以下是正经分析——

    其实还有一点是非常重要的:信息抹除。原接口设计和数据 /参数持久化是携带了类型信息的,被硬生生抹除了。
    接口 a 需要一个 int,传了个"0",
    接口 b 需要一个 string,传了个"0",
    接口 c 需要一个 bool,传了个"0"。
    他们默默做类型转换的时候,揣摩通透服务端的意图了吗?万一服务端真的 bug 了,就输出了一个错误的类型,你能察觉吗?
    这是信息抹除带来的第一个问题:错误被掩盖。
    第二个问题可能是某些人习以为常的:文档上说入参均为 string,但其实具体实现中会对他们做对应的转型操作。转错了程序当然没法正确执行。这使得人们更依赖所谓的文档,却直接丢弃了语言 /协议 /架构 /方案自身的自描述和自检能力。“最好的文档就是代码本身”这句话的价值不是为懒得写文档找借口,而是真正的金玉良言。
    第三个问题随着第二个问题而来,文档缺失和过期大概是实际项目中的常态,信息抹除所带来的额外信息恢复工作就变成了一项困难的事,增加更多不必要的成本和风险,以及团队沟通成本、技术管理成本。

    那么为什么很多“给别人用的接口”反而倾向于这样设计呢?容错性表面上能稍微好一点,而额外带来的风险和成本又不必自己承担。典型的就是给第三方用的接口、给其他部门用的接口、给其他团队用的接口。后端给 app 扔个这样的接口,不必沟通,不必争论,暂时性的增加了双方的幸福感。有种让他在团队内部同一项目内声明一堆 Object... args 的方法?怕不被自己人打死。

    说白了,这就是懒惰+短视+自私的人性抉择。
    hyyou2010
        92
    hyyou2010  
       2018-05-20 00:10:29 +08:00   ❤️ 1
    @james2013

    关于{desc:"null"},如果按我的想法,这里应该是{desc:""},从未设置过也是“”,也即只有文本字符串的概念。

    有很多 json 解析工具的确都可以处理 js 中的 null,然而不一定所有地方都用同一种解析库,也说不定不叫 null 而叫 nil,因而在项目中往往更看重接口的普通性和统一性,容错处理也是这样,这样才能避免坑。印象中---但我可能记错---接口定位为 boolean+int 和 Boolean+Integer 可能在解析包里面的处理就不一样,而这挺容易写混。诸如此类吧,我认为接口应该就平面无对象的,和语言无关,和解析库无关。
    huclengyue
        93
    huclengyue  
       2018-05-20 00:39:16 +08:00 via Android
    @flyingghost。。。。不敢苟同,相对的我认为懒人才更会选第二种,因为 json 解析库自带的功能。在对接不同语言,不同平台,不断试错之后选择的第一种并不是懒,或者自私。难道你们的语言里对象转 json 比转成第一种这样的方式更容易?
    james2013
        94
    james2013  
       2018-05-20 00:40:38 +08:00
    @huclengyue
    1.ios 中没有 true 或者 false,这个是很多替代方法:
    1)比如 ios 本地处理(不会 IOS,这这只是从网上搜索的,结果待验证,我想是有解决办法) "manage":true BOOL manage = [[content objectForKey:@"manage"] boolValue];
    2)实在不行,规定以 1,0 代替 或者字符串值来代替 true 或 false
    2.json 中我才不管你是 php 还是 java 后台,我公司后台 java/php/.net 都有,人家也不会告诉是什么类型,我也是根据接口返回值自己进行修改,觉得用户 id,订单 id 等需要 long 类型,就修改了.以前还真遇到过 GsonFormat 自动生成的是 int,但是实际上是 long 类型的.
    huclengyue
        95
    huclengyue  
       2018-05-20 00:44:24 +08:00 via Android
    @james2013 额。。。所以我们说的不冲突啊。。。
    flyingghost
        96
    flyingghost  
       2018-05-20 01:03:47 +08:00
    @huclengyue 战术层面的勤劳掩盖了战略层面的懒惰。任何语言里额外转一次 string 都是体力活,但好在不用动脑呀。
    相反,选择自带库不是懒惰,这是聪明的偷懒,因为脑力都耗费在设计上,耗费在方案选择上了。就算自带库不能满足需求(比如 js 自带 json 解析不能满足 long 需求)依然花力气去找轮子而不是造轮子。有现成的谁不爱用呢是吧。
    james2013
        97
    james2013  
       2018-05-20 01:04:28 +08:00
    @hyyou2010
    你说的接口跟语言无关,我是认同的.json 格式,是有其规范的.
    解析库也是依据 json 格式进行封装的,什么?连 json 格式中 null 都不支持的解析库,找一个正规的出来看看 ?. 像你说 nil 这种情况是不会出现的.
    json 的值就只有 string,number,true,false,null,object,array.这几种类型.如果只用 string,就要想想为什么 json 还要制定的其它类型
    以下是 wiki json 例子:https://en.wikipedia.org/wiki/JSON
    {
    "firstName": "John",
    "lastName": "Smith",
    "isAlive": true,
    "age": 27,
    "address": {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021-3100"
    },
    "phoneNumbers": [
    {
    "type": "home",
    "number": "212 555-1234"
    },
    {
    "type": "office",
    "number": "646 555-4567"
    },
    {
    "type": "mobile",
    "number": "123 456-7890"
    }
    ],
    "children": [],
    "spouse": null
    }
    waitwait365
        98
    waitwait365  
       2018-05-20 01:30:07 +08:00 via iPhone
    第一种很 low,第二种合理。
    但是其实第一种的最根本的想法是解决一些问题的妥协的土方法。尤其是不同团队或者不同公司间的对接项目。(比如:毕竟我接口就一个入口,改起来快,调用方 n 个地方调用这个接口,经常会出现改漏了测出来有问题再改再测,虽然本质是技术能力问题,但没辙,延期半天,谁想周末来加班,算了算了,我 /你 做下兼容。本质就是替别人买单或者别人替我买单)
    waitwait365
        99
    waitwait365  
       2018-05-20 01:38:41 +08:00 via iPhone
    还有一个比较有意思的事情:几年前了,我们接淘宝订单,有天 A 团队.net 的,订单服务有问题,后来查下来原来是淘宝一个字段的数据类型改了,B 团队订单服务却没问题,后来看了下原来处理订单的时候可能默认所有字段都是 string,计算的时候都强制转了下类型。A 当然没错,B 做法相当笨拙,但是结果是 A 被客户抱怨(后来没关注淘宝是不是又改回来了)
    hyyou2010
        100
    hyyou2010  
       2018-05-20 01:39:25 +08:00
    @james2013
    解析库也是依据 json 格式进行封装的,什么?连 json 格式中 null 都不支持的解析库,找一个正规的出来看看 ?. 像你说 nil 这种情况是不会出现的.

    ---------这里有个误会,我是说后台有可能送的不是 null,而是 nil 或其他。

    我的观点是,接口规范和 json 规范是两码事,接口设计不必遵循 json 规范,它们有不同的设计标准。
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2861 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 12:59 · PVG 20:59 · LAX 05:59 · JFK 08:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.