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

客户端不接收 null, 各位服务端大佬都是怎么优雅处理的?

  •  
  •   laaaaaa · 332 天前 · 4801 次点击
    这是一个创建于 332 天前的主题,其中的信息可能已经有所发展或是发生改变。

    环境

    jdk8, springboot;
    

    需求

    客户端包括了很多,电视端 手机端 小程序端 web 端;
    
    除了 web 端,好像都不太愿意接收 null ;
    
    例如 java 一个实体类 我返回给他们,某些字段为空的话 也想接收 "",不要 null ;
    
    
    这一块我想问问大佬们,都是怎么优雅处理的;
    
    不会要每个 bean ,都 private String a = "";
    

    ps

     1. 判断 Null  和 "" 有很大区别吗? 因为什么呢
     2.java 编译过程中,null 要比""占用的资源少吧
    
    第 1 条附言  ·  332 天前
    统一回复一下:

    序列化处理应该是可以的,@JsonInclude(JsonInclude.Include.NON_NULL)

    但是有几个点

    1.这个序列化,我在每个返回类上都要加这个 这个感觉好别扭- -

    2.我加上这个注解之后,会不会跟其他的序列化冲突啊,例如 这个返回类 我要缓存到 redis, redis 用的 fastjson 做的序列化;

    3.除了返回给客户端 为 null 的不反悔, 我在我的业务功能里 为 null 的时候 我也需要有这个字段,这也会有异常呀
    73 条回复    2024-02-01 14:54:03 +08:00
    doco
        1
    doco  
       332 天前   ❤️ 8
    web 端也不想要 null
    ZhLTE
        2
    ZhLTE  
       332 天前
    序列化的时候统一处理
    pota
        3
    pota  
       332 天前
    这么和你说 "" 和 null 不是一个类型的数据。你定义一个参数是 string 我塞一个 null 给你,你怎么想?
    laaaaaa
        4
    laaaaaa  
    OP
       332 天前
    @pota 大佬是怎么解决这个问题的
    pota
        5
    pota  
       332 天前   ❤️ 1
    @pota #3 手快发布了。这就不是麻不麻烦的事,作为一个 API 。保持数据格式一致是最基础的要求,还有 json 的{}没数据给[] 的时候也很恶心。
    falsemask
        6
    falsemask  
       332 天前
    spring.jackson.default-property-inclusion=NON_NULL
    laaaaaa
        7
    laaaaaa  
    OP
       332 天前
    @pota 对 还有这个问题,如果返回的是 json 或者 数组, 没有数据 我一般会给 [] 或者 {}, 但是服务端如果返回这样 貌似要 new 一个对象返回, 这不是又耗费资源了吗
    me1onsoda
        8
    me1onsoda  
       332 天前
    null 要多一步判空吧
    chendy
        9
    chendy  
       332 天前
    直接不返回就行
    或者让他们换一个完善点的 ui 框架,自动把 null 显示成空白那种
    azhangbing
        10
    azhangbing  
       332 天前
    因为 kotlin 默认非空
    wu67
        11
    wu67  
       332 天前
    举个例子.
    你这样返回的时候, JS 代码仔需要写多好几个判断来取数, 尤其是需要字符串内容做正则的时候
    if (typeof a === 'string' && /balabala/.test(a)) {}
    要不就是 if (a.length) 能解决的时候, 需要 if (Array.isArray(a) && a.length) , 看起来是没什么, 但是页面结构复杂度以上去, 数据字段一开始多, 这一大堆多出来的判断, 就会成为客户端代码的屎山
    NewYear
        12
    NewYear  
       332 天前   ❤️ 2
    1 、有的语言里,null 会报错。还会导致 if 判断不按预期的分支走。(特别适合用来写屎山,因为从语言层面你看不出任何一点不按预期分支走的可能,直到单独调试在这里才发现卧槽)
    2 、有的语言里,null 不会报错但是每次都要考虑它就显得很烦了,谁都不想增加负担。

    一般的解决方案:禁止 null 的存在,明确每个值的意义。

    未定义也不许用 null ,字符串可以用"",数字可以用 0 或者-1 (具体按自己的定义来)。
    数字类型:1 是男,0 是女,-1 是未定义
    又或者 0 是未定义,1 是男,2 是女,3 是跨性别男,4 是……

    字符串类型:""是未定义,"男"是男。

    日期类型:“1970 年 1 月 1 日”是未定义,或者“0000 年 00 月 00 日”是未定义。
    MoonLin
        13
    MoonLin  
       332 天前
    不返回的话他们可以自己用默认值,返回为 null 就覆盖了默认值,如果要处理的话其实也可以,自己实现反序列化就好了,但是我估计客户端不愿意干,不然你也不会来问了。所以你不如直接不返回,看你用什么序列化框架,一般如 6#所述加个注解就好了。
    NewYear
        14
    NewYear  
       332 天前
    null 和 string/int/date 的类型都不同,不能直接用真的很烦。

    楼主后端用是什么语言,不是强类型语言吗。
    sanmaozhao
        15
    sanmaozhao  
       332 天前
    我觉得应该返回 null ( OP 没说返回的数据格式是啥,默认 JSON 了)

    1 、JSON 里面本来就是有 null 这个类型的
    2 、数字型,不返回 null 的话,用什么表示这项数据没有值呢?用哪个数值都不太合适
    如果没值的项直接不返回的话,其实和返回 null 差别也不大
    比如对于 js ,就是判断 undefined 和 null 的差别
    wu67
        16
    wu67  
       332 天前
    还有一个典中典的, 忘记是什么时候遇到的, 有个变量的值, 是 'null'...

    出 bug 找前端查的时候, 那一个山崩地裂...

    if('null') {1} else {2}
    // 1
    null123456
        17
    null123456  
       332 天前
    调用此方法:StringUtils.isNotBlank(String str)
    vagusss
        18
    vagusss  
       332 天前
    springboot 默认的序列化应该是 Jackson, 应该有配置项可以直接达到你要的效果
    lyxxxh2
        19
    lyxxxh2  
       332 天前
    啥类型的就返回啥类型 很正常
    web 端口也一样
    字符: ''.split('a')
    数组: [].map((() => {})如果返回个 null,前端: mmp
    cslive
        20
    cslive  
       332 天前
    加注解,字段为 null 会忽略 json 序列化
    yxisenx
        21
    yxisenx  
       332 天前
    jackson 的话直接在返回实体上面加个
    @JsonInclude(JsonInclude.Include.NON_NULL)
    potatowish
        22
    potatowish  
       332 天前 via iPhone
    返回空字符串和 null 在服务端含义是不同的,而客户端是表现层,所以这个差异是体现不出来的,都是没有值。

    还有就是代码健壮性的问题,如果客户端处理了 null ,那么即便服务端返回空字符串,客户端也不会有问题。
    nicocho
        23
    nicocho  
       332 天前 via Android
    好久没看到优雅这个词了
    sanmaozhao
        24
    sanmaozhao  
       332 天前
    @potatowish
    > 返回空字符串和 null 在服务端含义是不同的,而客户端是表现层,所以这个差异是体现不出来的,都是没有值。

    这个其实不太对,现在的客户端早就不是简单的渲染表现层了,也是有部分业务逻辑在里面的
    所以我上面才觉得,服务端就应该如实地返回 null
    XXWHCA
        25
    XXWHCA  
       332 天前
    null 不返回就行,他们可能是不喜欢返回没有意义的 null 字段,客户端这种强类型语言开发时不返回的字段引用类型默认值也是 null😂,文档写明白就行了
    kalista
        26
    kalista  
       332 天前
    go 也不喜欢 null ,甚至数据库定义里面都是 not null 的
    Ayanokouji
        27
    Ayanokouji  
       332 天前
    数据库加默认值,能解决不少问题
    yolee599
        28
    yolee599  
       332 天前   ❤️ 1
    为啥要返回 null ?没意义啊,如果这个字段没有数据,直接不传这个字段就好了,不用多此一举还浪费网络带宽。
    treblex
        29
    treblex  
       332 天前
    我最近开始写 getValue(obj,"a.b.c.d") 这样的东西,取到 null 的时候就不会崩溃了🙈
    ZeroDu
        30
    ZeroDu  
       332 天前
    正确操作是直接不序列化这个字段。别返回空字符,这种才是
    wangritian
        31
    wangritian  
       332 天前
    我是 go 后端,用中间件拦截控制器的输出,然后通过反射递归的把空指针 nil 改成空值
    但其实站在团队角度,我更支持客户端应该有健壮性,兼容 null 和空值
    就像我从来不设计请求参数不传(null)和传空值有不同含义,应该最大的去兼容
    nerkeler
        32
    nerkeler  
       332 天前
    `private String a = ""` 简单粗暴,或者用注解 @JsonIgnore 指定参数(具体忘记是啥了) 不返回 null 的字段 ,怎么简单怎么来呗,或者统一处理请求字段 null 的都给个初始值,不过实现麻烦了点
    broken123
        33
    broken123  
       332 天前
    你应该想想各个客户端的语言是不一样的 安卓 java kotlin ,flutter dart web js ts , 还有各种小程序 直接给一个默认值就行了
    broken123
        34
    broken123  
       332 天前
    实际上客户端也只有强制类型语言才会 做 null 判断 js 会 出现 undfi 和 null 这种情况 java 写他妈一大堆非空判断再取是真的很烦心。代码丑陋的一笔。
    darkengine
        35
    darkengine  
       332 天前
    有一天,后端跟我说,前端要判断某个接口返回的复杂结构里字段是不是 null 或者 undefine

    我问哪个字段需要判断,他说不是很简单吗,所有字段。。。

    卧尼🐎个很简单
    zjp
        36
    zjp  
       332 天前
    在序列化层做呗,Jackson 的话是单独处理 null 值的,参考 https://stackoverflow.com/a/18123772
    JsonInclude.Include.NON_NULL 的结果是没有字段
    linzhe141
        37
    linzhe141  
       332 天前
    前端加一大段```a?.b?.c?.d ?? "无数据"```
    zjsxwc
        38
    zjsxwc  
       332 天前 via Android
    我写 js 就喜欢 null ,

    如何某个字段是 object , 但这个 object 数据没有,那你也必须给我一个 null 值,不然如果你直接不给我这个字段,我 js 取这个字段时就直接报错执行不下去。
    zjsxwc
        39
    zjsxwc  
       332 天前 via Android
    我写 js 就喜欢 null ,

    如果某个字段是 object , 但这个 object 数据没有,那你也必须给我一个 null 值,不然如果你直接不给我这个字段,我 js 取这个字段时就直接报错执行不下去。

    如果某个字段是 int ,你却给了我一个 0 ,我怎么表示,这是业务上比如用户还没填写,还是用户已经填写了 0 ,string 也一样道理。
    xuanbg
        40
    xuanbg  
       332 天前
    null 就是 null 。又不是我要给 null ,肯定是你前端没给数据数据库里面才存的 null 。你前端凭啥不要 null ?
    mshadow
        41
    mshadow  
       332 天前 via Android
    @pota {}给[],一般是后端 php 的坑,map 和数组在 php 中都是 array ,空 array 会 json 序列化为[],这个一般要 php 特殊处理一下
    oatw
        42
    oatw  
       331 天前
    有一种主义叫“无 null 主义”,数据库里就不可以有 null ,尤其是涉及到三值逻辑的时候。
    DzwsGo
        43
    DzwsGo  
       331 天前
    kotlin 默认非空,如果没有做特殊处理 json 转换的时候遇到 null 就会崩溃,做处理就会出现很多?
    另外
    @chendy #9 后端是不是可以换个完善点的框架,自动把 null 换成相应数据类型默认值? 😁
    pota
        44
    pota  
       331 天前
    @laaaaaa #7 java 应该没有这个问题吧? map 结构化之后就是{}啊。像楼上说的,PHP 会有这个问题。API 数据类型一致因为我不是 java ,一般我解决方案就是可能出现类型不一致的定义 Attribute 获取
    cleveryun
        45
    cleveryun  
       331 天前 via Android
    前面有楼层提到数值没值返回 0 不合适时返回 null 的。这个没业务场景的情况下且认为没问题。这里其实他们说的最大问题不是是否返回 null ,而是与接口文档是否一致。如果会返回 null ,那接口文档里就不应该只写会返回数值,应该把 null 也写上。这是联调涉及到的契约精神的问题,不应该字段值类型都变成盲盒。
    chendy
        46
    chendy  
       331 天前
    @DzwsGo 写过 kt 和 ts ,需要?的时候就给?呗,业务逻辑允许 null ,代码没理由不允许 null (其实展示层还好,如果有逻辑啥的就比较麻烦,有时候甚至原样复制粘贴但是去掉?然后加校验和报错)
    这么一说其实塞默认值可能在序列化这一步更合适?
    字符串就 "",列表就 [],但是对象和数字不好处理,特别是需要区分‘填了’和‘没填’,需要有‘草稿’这类的功能的时候更是如此…
    j1132888093
        47
    j1132888093  
       331 天前
    整型的 null 和 0 ,字符串的 null 和空本来就是不同的意义,凭啥不要 null ?你要是说 null 就直接不返回这个字段还能理解
    wangtian2020
        48
    wangtian2020  
       331 天前
    返回的 json 出现 null 或者是 undefined 我立马活都不干了跟后端去 battle ,所有字段必须初始化成空字符串/空数字
    2123123
        49
    2123123  
       331 天前
    字符串空跟 null 的绝大部分时候意义是一样的,所以字符串我一般初始值给 ""
    但是空数字意义是不一样的,非要传个特定数字或者 "" 代表空的话也要多一次判断,跟判断一次 null 本质上不是一样吗?
    leonshaw
        50
    leonshaw  
       331 天前
    幼儿园就讲过的问题,0 不一定是没有,白色不等于透明
    jl1014171068
        51
    jl1014171068  
       331 天前
    null 也还能接受,但是还有返回"null"的..........
    dyv9
        52
    dyv9  
       331 天前 via Android
    对于数字栏,有时候没填写和 0 意思是不一样的。
    BBCCBB
        53
    BBCCBB  
       331 天前
    OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);

    这样直接就不返回那个值了, 一样有问题.
    最好的办法就是前端判断..
    xingdaorong
        54
    xingdaorong  
       331 天前
    @zjsxwc 你说的不合理,假如 age 字段不填,可以返回 null 不能 0,因为含义不同一个没有年纪,一个是 0 岁,字符串比如名字,可以是 null 可以是"",但是最好是"",因为前端可能用字符串方法不做判空报错。但是比如一个数组,没有数据就是空数组[]而不是 null 。总结:如果没有特殊含义就一定用同类型的,不用 null 。
    exmario
        55
    exmario  
       331 天前   ❤️ 1
    null 还好说,但是给个"null"算什么回事
    zjsxwc
        56
    zjsxwc  
       331 天前
    @xingdaorong
    我还是坚持除了 array 必须用空数组[]外,别的全都可以 null 。

    如果你不允许 null ,那么对于任意字段 XXX ,你必须额外添加一个字段 isXXXNotNull 来表示,XXX 字段是没有被填写状态还是已经被填写了。
    lujiaosama
        57
    lujiaosama  
       331 天前
    我最讨厌的是数字型字段原本该返回 NULL 或者''. 给我返回了个-1. 问题是-1 有些场景在业务上是有意义的. 直接显示个-1 容易误导用户.
    wmui
        58
    wmui  
       331 天前
    不是不能是 null ,是要保持数据结构一致。如果是数字,默认值可以是 0 不能是 null ,如果是字符串,默认值可以是'',如果是对象,默认值可以是 null
    zerofancy
        59
    zerofancy  
       331 天前
    我们是基本类型一般不要有 null ,这样客户端可以定义 int 而不是 Integer 。其他类型包括 String 都当作可能为 null 来处理。
    尽管我们用了 Kotlin ,但序列化框架还是 gson ,所以一般还是把几乎所有字段定义成可空的。
    Jhon11
        60
    Jhon11  
       330 天前 via iPhone
    用 protobuf
    yusheng88
        61
    yusheng88  
       330 天前 via Android
    1. null 和默认值是两个概念,null 是没有值,判 null 是调用方的责任
    2. 字段能否为 null ,是产品,业务决定的,如果有默认值,也是产品和业务决定的。
    3. 字段为 null ,或者为 null 时不返回字段,前端处理不了的,领导还倾向前端的,只能对你表示可怜
    liuhuihao
        62
    liuhuihao  
       330 天前
    个人观点

    String 空值情况:空值一律返回'',理由是一般情况下字符串字段都是用来展示用的,如有逻辑判断<用户是否填了>这个字段,那可以增加一个 boolean 字段表示是否填了, 但这种情况业务上很少,因为作为入参的时候一个输入框没填其实 = 空字符串

    Number 空值需要根据业务场景来处理,比如“好友数”等各种计数的空值可以是 0 ,男女等 未选择的话可以用 -1 表示。但如果是一个非必填数字输入框,可以输入任意值的这种,null 值 应该是需要的

    Boolean 同 Number ,需要根据业务场景来处理。

    Array 空值一律应为 []

    Object 不应返回 null ,比如“人”这个对象有个字段叫“父亲信息”,有的人可能没有父亲,这种情况 “父亲信息” 字段不应返回 null ,而是在“父亲信息”这个对象里面的 “是否存在父亲”字段做判断

    总结我的观点:除了 Number 和 Boolean 可以返回 null ,字符串、对象、数组都不应返回 null
    liuhuihao
        63
    liuhuihao  
       330 天前
    @yusheng88 产品和业务决定的应该是 字段是否可以为空,帖子讨论的为空的时候接口是否该返回 null 。很多值为空时候返回其实是可以在接口设计阶段避免的。
    个人理解,如字符串 null 和'' 其实是一个含义都表示没填,数组[] 和 null 其实也是一个含义都表示没有。对象则应该在对象内部增加字段判断是否存在,Number 和 Boolean 大多数情况下也不需要返回 null 。
    QlanQ
        64
    QlanQ  
       330 天前
    我比较赞同 #58 的观点
    接口的基本原则就是 数据结构必须一致,如果你的这个数据定义是 string 那这个值没有设置之前都是 '',不应该是 null
    上面有说 如果是 null 就不返回的情况,这种我见了就直接打,你都是强类型语言了,返回的结构还不一样?我在判断一个数据的值是不是真之前,还要考虑这个值存不存在?

    两个例子,现在已经有 1w 用户了,突然加了个需求,用户可以弄一个签名,类似 QQ 签名,这个时候,你要加表字段,按楼上一些人说的,那这个用户没有设置过,值应该是 null 是吧,那现在一个用户设了签名,后面又清空了签名,那你在保存用户的签名时候,是改成空字符还是 null ?你返回的数据是什么?

    上面提到年龄,如果这个字段的信息是保存用户的年龄,那 null 是什么意思呢?
    liuhuihao
        65
    liuhuihao  
       330 天前
    数据定义和返回必须一致,这个我支持。你可以看下 我 62 楼的回复,有些情况下 null 还是有必要的。比如一个非必填输入框只支持填写任意的数字,那么这种情况下 我这边通常在定义这个字段的时候就定义为 number | null ,用 null 来表示“没有填”。
    xingdaorong
        66
    xingdaorong  
       330 天前
    @zjsxwc 没听懂啥意思,这个是否被改写的状态真实业务场景的状态是啥,很多不需要这个字段
    yusheng88
        67
    yusheng88  
       330 天前 via Android
    @liuhuihao
    1. 我的评论应该很清楚,接口该返回 null 就返回 null
    2. null 和"不是一个东西,等你什么时候调用接口后不用对 string 返回值判 null 再讨论这个吧。
    3. 集合,容器类推荐返回空集合,因为关注的是容器内的元素,而不是容器,容器应该存在的
    liuhuihao
        68
    liuhuihao  
       330 天前
    @yusheng88 #67 没理解你的意思。我们这边接口针对 string 、数组、对象 类型前端确实是不需要 判 null 的,因为约定的是啥类型返回就是啥类型,空值也一样,string 类型为空时当然应该为空字符串,null 又不是字符串类型,类型定义和数据返回的类型应该一致。
    jones2000
        69
    jones2000  
       330 天前
    null 字段,直接不要返回就不可以了, 还能节省流量。
    yusheng88
        70
    yusheng88  
       330 天前 via Android
    @liuhuihao
    话不投机半句多
    你保持你的接口返回值没有 null 就行了。
    不用再回复,没兴趣解答。
    lancelock
        71
    lancelock  
       330 天前
    空数字是各什么概念,哪个数字是空的?
    Coder89757
        72
    Coder89757  
       330 天前
    @doco #1 主要原因是给了 null 之后,解构取值兜底逻辑会直接失效。。。

    ```javascript
    const { str = '' } = response;
    // 假如 str 直接不存在,对象中连这个属性 key 都没有,前端拿到的 str 就是 undefined ,此时会兜底成空字符串,下面这个语句会正常运作,UI 正常渲染
    const newStr = str.replace('foo', 'bar');
    // 假如 str 传了 null ,这里直接 error 了,假如这段逻辑在 React 或者 Vue 渲染逻辑里面,这块 UI 直接就白了
    ```

    核心问题还是在于,这种做法改变了返回字段的类型,把前端或者客户端,抛进了类型判断的屎山地狱
    DzwsGo
        73
    DzwsGo  
       329 天前
    @chendy
    #46
    说的很对,但是答非所问,自己的逻辑 null 很好处理,但是接口里如果冷不丁返回 null 的话,做处理就会所有的参数都加上?,不做处理转对象的时候就会崩。
    #9
    这跟 ui 框架没有关系
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1018 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 22:22 · PVG 06:22 · LAX 14:22 · JFK 17:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.