V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  BeautifulSoap  ›  全部回复第 24 页 / 共 102 页
回复总数  2027
1 ... 20  21  22  23  24  25  26  27  28  29 ... 102  
@gogogo1203 这个帖子最初就一个目的:问怎么解决 null 解析问题,然后这个问题在前 20L 前已经被解决了。

但接下来我要说的话就不客气了

但是你要不要仔细想想猜为什么后来会发展为吐槽?因为我是真的被回复中的几位整烦了。
这个帖子 20 多楼之后除了少数几个回答可以看出真的有经验,回答是有用的之外,是不是一大堆自以为是、好为人师人的人一副教育人的口吻在提方案?提的方案还暴露了他们根本就在这方面毫无经验这回事。我就问,这贴已经有多少人说 null 解析是 validation 的问题?而这些说 validation 的人有多少人是能想到 null 解析是根本无法靠 validation 解决的?还出现了好几位“测试干什么”的主。更有说让人把一切字段定义成指针这么离谱方案的,最后被我拿例子怼眼前说在项目中用指针不现实反倒没下文了。

再比如说你,你自己扪心自问,你在 29L 和 35L 代码是不是展示了你最开始甚至连 json 解析 null 会出问题都没注意到?也不知道 null 解析成 0 会导致无法 validation ?我来猜一猜,你是不是被我指出有问题之后为了反驳我才去仔细读了 json 官方文档,才第一次知道 json 解析 null 值会有”我们认为 null 经常代表空所以跳过赋值”这一特性?
就好像上面好几位都在说“int 不是指针所以遇到 null 赋值 0 是合理的”一样,说这话就证明根本不知道是怎么回事硬要来教育人是不是?
PS:你再仔细看看我顶楼里的怎么说的 “尤其非指针类型字段,我下意识认为遇到 null 是会直接报错的,结果直接是当作不存在(undefined)来处理。。。”仔细想想
@lujiaxing 别逼逼
1. "请问你能教教我 json 这种 null 解析逻辑我该怎么做合法性校验呢" 静听高论,希望你能提出切实有效的方案而不是在这纸上谈兵。这个问题我自己已经解决了,只是像听听你会有什么更好的解决办法
2. 冷知识,实际项目中,外部接口可不光团队内部接口,还可能包括很多质量参差不齐对接的第三方非本公司服务的接口哦
3. 你是这个帖子第三个还是第四个动不动就问”测试干嘛去了”的人了。现实世界中测试不可能覆盖掉所有情况,总有纰漏,即便花费大心思去思考各种边界条件总归会出纰漏,对于复杂业务你想破脑袋现实都会给你一巴掌。而一有纰漏就质问“测试干嘛去了”的人,我觉得嘴脸十分丑恶
4. 我只问你一个问题你同不同意“后端不应相信前端/外部接口传来的数据”这一准则。如果你同意,无论你的团队编程质量多高,你就应该以最坏情况去写代码,你死鸭子嘴硬说永远不可能传 null 不校验那就是你自己都不遵守这一准则,把安全性的一切交给外部接口
@pkoukk so ,这和你搞双标有哪怕任何一点关系吗?
ps:解决办法 21L 就说了已经找到方向了。json 包魔改了一下加了一句判断工作良好已经用到项目里去了。这贴之所拉这么长,是真的太多人的回复(包括你)过于离谱了。就比如这个帖子里所有说这 null 解析是 validation 问题的,明显就试都没试过就一副很懂得样子教育人是 validation ( json 包这个特性实际上根本就没法做 validation )。再比指针,我 2L 就说过为什么不现实了,你硬是要教育人强行说它现实一样
@lolizeppelin 你别说,在踩到 null 这个坑之前可能真的挺多人都注意不到这个问题。而且你说的怎么感觉好反思怪啊。学语言总有没有注意到或记住的细节,出问题或者被人指出来前是很难发现的。约定好非 null 但传了 null ,属于不太常发生的事情,所以才很久没出问题。但墨菲定律就是这么发生了,出了事故了

@pkoukk 你做人怎么能这么双标呢?自己提出所有字段定义成指针,然后被我指出倒腾指针反人类后就提出让我再多写一层 struct 转换过去,在业务层倒腾 struct 。结果我的项目就是这么做的却反过头来说这是臃肿抽象? ps:我不会写 java 谢谢,我和 java 关系最近的也就是曾经学过一小会 kotlin ,仅此而已。项目分层无关语言是几乎所有复杂点的业务写到后来都会自然而然分的。我很喜欢 Go ,但对于像你这样动不动就让人在自己身上找问题,攻击其他语言的 Go 的小部分拥趸,真的很令人不适
@lujiaxing
1. 你和 ls 几位一样,我只是随便举个价格的例子而已你就只抓表象问题说事,遇到的业务问题不是价格也不是订单,只是订单更加容易理解
2. 我从来说的都是前端/外部接口解析的问题,请注意后者“外部接口”。你真的以为“金额/SKU 摘要/标题等是要你从订单里翻出来的!!”不会遇到 null 解析问题?假设你有订单 id ,然后订单详情需要请求另一个微服务 API 获取,这个 API 以 json 形式返回订单详情。好了,问题来了,这个微服务出了 bug 原本约定好禁止返回 null 的订单的金额、数量返回了 null 。请问你如何应对?请问你不还是遇到了同样的问题?这个问题不光是前段的,只要涉及到外部接口和 json 就会遇到

还有,请问你能教教我 json 这种 null 解析逻辑我该怎么做合法性校验呢?
@lujiaxing
@sylxjtu
内啥,莫纠结未知字段、未设置字段。这个帖子争论的重点还是在 null 的解析上。

@maggch97 说得很对,实际做了这么多项目后的感叹就是,实际复杂点的业务项目要考虑的问题太多了。光是一个外部交互检查有问题,或者业务逻辑层考虑不周全就很可能导致后面业务流程出大问题。虽然业务代码已经进最大努力将所有能想到的情况都检查了,但实际项目运行中依旧会时不时出现一个完全意想不到 case 导致出问题。
@pkoukk 我觉得包括你在内,很多人都有个问题,问的时候都一个个口口声声说后端不能信任前端/外部接口传来的数据,实际真的干起活来怎么就觉得不用遵循这一基本要求了呢? API 文档约定是一回事,实际过来什么数据只有天知道。作为后端肯定要以所有字段都可能被瞎传入 null 为前提考虑问题,遇到约定不能传 null 的字段传 null 了就报错,这难道不是后端的基本素养和常识?

其次,不好意思,作为用 Go 参与了 N 个复杂业务项目的表示,请求从 DTO 进来、转成 Entity 处理业务逻辑,最后在 repository 层里转成 model/DO 是我写项目的基本要求。但问题来了,json 解析不光出现在 DTO ,我请求外部接口也要解析 josn 哦。你说的全部定义成指针,那么这意味我一切 API 的一切 DTO 字段,所有请求外部接口解析结果获得的字段都要定义成指针,当然转成 entity 后业务层是不用太在乎,但我只能说,哦,真的太优雅了,工作量真的是太不饱和了。而且,即便是 DTO 层和外部接口请求也多少会有点和业务无关的逻辑的,让你对这些指针倒来倒去是真的不切实际的提案。哦,你说在 DTO 和 Entity 之间在加一层 struct 专门用来处理 DTO 层的部分逻辑?哦,见到这样写的代码大概率我会拒绝 review 的,因为照你这样搞这个项目 DTO 层漫天飞舞的指针就是今后屎山的起点
@gogogo1203 这就涉及到 49L 吐槽的的核心内容了。这 often 真的是 often 吗
@rekulas 我觉得你反倒很令人费解,请问你真的有业务经验吗,我说的都是实实在在经手的项目中遇到的问题。实际复杂业务中,前端/外部接口根据需要传过来的 json 包含这么多字段不是很正常的?其中个别字段为可 null 难道不正常?我给你的这个 Data2 就是我目前一个项目的 DTO 定义(当然类型并非全都是 int ,数量规模差不多这种感觉)

作为后端的基本要求就是不信任外部输入,我就只能考虑以这些字段都可能被传入 null 。你说全定义成指针可以解决问题,那么我就定义成指针了,结果就是我给的例子中的样子为什么反倒说我极端。。。。而且你要知道一旦涉及到业务,也就不是例子里简简单单的取值相乘了,根据 nil 不 nil ,计算方法不同等等等等一大堆复杂计算,全都是要对这些指针倒腾来倒腾去的,所以我才说不现实
@rekulas 典型站着说话不腰疼。我写了个例子给你展示所有字段都为指针是什么地狱情况
https://gist.github.com/WonderfulSoap/18a14da135f659d5350f36bdbe439b6a
真的太优雅了,是吧。main2.go 用来模拟在其他包里调用 Data2 数据的情况。悄悄跟你说 Calculate() 里已经塞入了两个 bug 了哦? data.I 和 data.Obj1.I 是可 null 字段段,所以不能直接取值。那么问题来了,如此高的心智负担这么多指针倒来倒去,你怎么确保你每次取值都取得万无一失?
@houshuu
> 如果"需要对传入的数据做最低限度的确认", 那么就应该用指针. 因为这句话的背后已经说明了有可能为 null

你好,你这已经是我针对不同人提出的同一个问题的第三次回复了。定义成指针是没有可行性的做法。理由很简单,作为后端我必须不相信前端,所以我要考虑 DTO 的所有字段都有可能被前端瞎传入 null 的情况。
如果采用指针的话,这意味着我一切 struct 中每一个字段都必须定义成指针。这根本不现实对吧?整个项目 DTO 中所有字段全是指针用起来一定很酸爽对吧。再一个,实际项目中 API 并不是所有字段都禁 null ,个别字段是允许 null 的,所有一切字段都定义成指针的话,请问你能轻松分辨出这一堆指针类型的字段中,哪些是允许 null 哪些是禁止 null 的?更要命的是,使用字段值的时候到底哪个字段要加*,哪个字段要判 nil ?

> 如果连测试都不需要

不好意思,不是没有测试而是测试没有覆盖到。你如果认为所有项目只存在完全没测试和所有测试条件都覆盖到的两种极端的话那就太理想了

> 不是自己的锅别接, 别人再怎么说也改变不了这个不是后端的问题

不是的,锅的确不是自己的我也不会接,但是因此产生的生产事故和因为事故调查、恢复加的班是实打实(你不可能叫前端过来给你查后端 l 日志,抽取数据回复被破坏的生产环境)
@lshang 你说的非常对,你说的这个情况其实就是我顶楼给的几个例子中之一

解析下面的 json 都会成功,解析结果就是所有没有填的字段全为空值

{"a": "a"}
{}
{"obj": {}}
@rekulas 我不知道是自己说明能力太差还是你没法理解,我举例 python 、php 、js 只是想说他们都会将 json 中的 null 解析成对应语言中的 None/null 。这点你能明白吗?然后在 Go 语言里,与 json 的 null 最接近的概念也就只有 nil 了,你同不同意?所以将 null 的解析为 nil → 而非指针类型无法赋值 nil 从而会引发解析错误难道不是非常自然的想法?为什么你会认为这是个校验的问题呢?

而且如果要较真的话,我们再来深入思考一个问题,什么才叫校验?你说 null 解析成 nil 赋值给非指针字段是校验问题,那么解析如下 json {"a":"hello"}到 这个结构体 struct { A int} 是不是也应该归类为校验问题? 在这里 A 是 int 类型,但是传入了字符串,两者的类型不对的检测是不是也应该交给校验?按照你的说法,解析 { "a": "hello"} 的结果就应该和{"a": null} 一样都解析成 0 ,然后交给校验来处理是不是?
@gogogo1203 #33 “前端来的 json 用一个 struct, 校验完” 其实问题就出现在怎么校验这一步上啊。null 会被解析成对应字段类型的空值,也意味着根本没有手段去校验 json 传入的是不是 null 。问题就出现在这一步了。我顶楼给的那几个涉及到 null 的例子就是最好写照
@gogogo1203 这方法使用 DisallowUnknownFields 能解决问题 1 ,但问题 2 没办法解决
@delacey 我顶楼也说了,直到踩到坑之前我都一直以为 json 包替我完成了对 null 的校验啊。你要想,json 包做解析的时候吧 string 解析到 int 类型字段会报错,那么谁会想到把 null 解析到非指针字段就不会报错了呢?

> 都是不出事就注意不到的问题。尤其非指针类型字段,我下意识认为遇到 null 是会直接报错的,结果直接是当作不存在(undefined)来处理。。。
@houshuu 你可能都没看懂我这贴的意思到底是什么。我只是举例,出的事故不是订单相关。

后端不应该信任前端/外部端口传入的数据,所以后端需要对传入的数据做最低限度的确认,如果不符合预期和要求就要报错。请问这点你同不同意?
这次问题就出在“对传入数据做最低限度的确认”上,API 接口约定不能传 null ,但是外部接口传了 null ,在 json 解析的时候自然而然会认为要给非指针赋值 nil ,json 包肯定会报错,但实际上它解析成空值不报错,而空值 0 是业务允许的,从而引发了生产事故

自然,传了 null 的确是前端/外部接口的锅,但除了生产事故加班 log 调查、数据查找、确立回复数据库数据都是后端/运维的工作。到时候如果来一句“虽然 xxx ,但后端连 null 都不检查的吗”就问你怎么应对。
@Maboroshii
@kumoocat
“Go 不用指针就代表不能为 null”
“那你知不知道,golang 里面,struct 只有 0 值没有 null 值呢”

你们说的对啊,Go 里一个类型不是指针代表这个类型不能赋值 nil ,json 解析的时候遇到 null 意思就是要把 nil 赋值给非指针,直接报错不是再正常不过的想法吗?


“你也知道,你列举的这些语言,对象是可为 null 的”
这里面和 go 最相近的是 Go ,因为 kotlin 和 go 一样类型分可空/非可空(对应到 go 近似看成指针/非指针)。当尝试将 null 解析到非可空字段时,kotlin 是可以报错的
@tairan2006 要改成指针的可不止匿名类,匿名类里的 AA 、BB ,外面的 A 和 B 也都得要改成指针哦。然后就出现了我 2L 说的问题,为了解决 null 判定这一个问题,整个 struct 全部字段都定义成指针,实在过于得不偿失了。

@Maboroshii 其实问题不在“已知字段会为 null”,而是 API 文档已经明确约定了些字段全都不能为 null ,但外部接口/前端就硬是给你传了 null (不要问为什么,后端永远不能相信前端传给你的数据是什么牛鬼蛇神,实际上这次出事就是因为约定了非 null 的字段外部接口给传了 null 。)
@haoxue 多谢我试试
@tuxz 正常来说一个实际的项目中,要从 json 解析出 struct 的数量是几十上百个的。。。一个个实现不太现实,写通用方法塞进去倒也是个办法,但是也容易出纰漏


@ye4tar
@RedisMasterNode
是的,我思前想后可能也就只能自己魔改官方 json 包了。不过倒也用不着 validator ,直接在解析 json 的时候,如果目标字段为非指针类型,遇到 null 就直接报错可能会更直接的。一直不太想自己魔改主要是总感觉自己写的东西是重复造轮子,,,,
1 ... 20  21  22  23  24  25  26  27  28  29 ... 102  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   982 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 20ms · UTC 19:40 · PVG 03:40 · LAX 12:40 · JFK 15:40
Developed with CodeLauncher
♥ Do have faith in what you're doing.