V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
STtree
V2EX  ›  Node.js

“使用抛异常的方式返回校验不通过的结果”是不是一个好的处理方式?

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

    我正在写一个 Express 服务,其中有个地方需要校验用户的输入。我的处理是在校验不通过后抛出一个异常,由全局的异常处理来返回 400 响应。我的同事觉得我这种处理方式不行,他的理由如下:

    • try catch 会增加性能开销
    • exception 应该用于 error handling

    我觉得有些道理,但是我之前写 Java 的时候看到过很多这种用法,而且我觉得这种用法写起来也比较方便。难道这真的不是一个好的处理方式?

    31 条回复    2023-08-21 09:49:32 +08:00
    cxtrinityy
        1
    cxtrinityy  
       257 天前 via Android
    Nodejs 不知道,Java 的确挺常见的,相比于增加的一点性能开销,try catch 带来的好处也不少,这种情况往上抛异常一般表示这个异常你不需要处理,往上抛上层自然有别的方法来处理,一层层往上走即可,直到抛到顶层。如果你自己去处理这套逻辑,可能比较麻烦,容易出错,而且为了这点性能,真的有必要这样作么?这是个平衡问题,不知道同样道理适不适用于 nodejs
    airyland
        2
    airyland  
       257 天前   ❤️ 6
    绝大多数网站没有到需要考虑 try catch 性能开销的用户量。
    vchroc
        3
    vchroc  
       257 天前
    是。他的这两个理由都很牵强
    makelove
        4
    makelove  
       257 天前
    非常合理,这类目的直接返回简单 400 回应的用户输入异常就是 exception 。

    除非是表单校验之类预期用户会输入不合理数据并要给出相应提示的情况下不用异常来处理也合理。
    picone
        5
    picone  
       257 天前
    理解不一样吧,try catch 倾向于程序处理中的未知错误,表单验证是 if else 能处理的。他是不是 C/Go 等语言过来的😂
    dzdh
        6
    dzdh  
       257 天前
    我理解 try...catch 是处理逻辑异常,TypeError 、BoundsError 也是逻辑上的异常,逻辑上传错了类型,接收错了类型。

    程序错误,抛出异常给 500 响应,逻辑异常给 400 响应没毛病
    sujin190
        7
    sujin190  
       257 天前
    验证不通过其实就是输入错误难道不是 error 不应该走 error handling 么?谈 try catch 会增加性能开销那更是扯淡,不是说没有性能开销而是实际业务中纠结这个毫无意义
    Chad0000
        8
    Chad0000  
       257 天前
    以前我指向返回 Result 带 Success 与否,现在我直接抛异常,异常类型统一定义方便统一截获处理。比如数据验证异常就可以友好返回。

    好处是代码写起来很简洁,Fail First 。
    zhengwenk
        9
    zhengwenk  
       257 天前
    动不动就性能开销,cpu 和 内存发展的那么快不就是给你开销的么。都不开销,放着看么
    fgwmlhdkkkw
        10
    fgwmlhdkkkw  
       257 天前
    try catch 没有开销,跟你正常判断一样。
    nothingistrue
        11
    nothingistrue  
       257 天前
    如果 “ try catch 会增加性能开销” 有道理, 那不止 Java , 大部分语言都要回炉重造。不过这个确实看语言框架。
    “ exception 应该用于 error handling”,这就是纯粹的胡说八道,用户输入校验不通过,这不是错误,那系统就没有错误了。当然,既然用了 exception ,那就得什么样的错误配什么种类的 exception ,别无脑什么错误都抛出同一种 exception(msg )
    Masoud2023
        12
    Masoud2023  
       257 天前
    Java 基本也只能这么做吧
    libook
        13
    libook  
       257 天前
    用 Java 、Node.js 不需要考虑性能问题,大多采取微服务集群的方式就可以消化并发负载,真的是单个请求有性能问题,应该在有问题的这部分使用 C++、Rust 等语言使用高性能方案处理。

    个人认为关于代码,最重要的是可读性,其次是可扩展性,最后才是性能。

    异常会有很多种,有的需要返回 400 ,有的需要返回 401 ,有的需要返回 403 ,等等。如果你定义好了不同类型的 error ,然后可以根据 error 类别来精准返回错误信息,且同类 error 的返回信息在未来有可能会统一修改,那么全局处理可能会让代码更简洁、清晰一些。你只需要处理好 error 的 stack ,确保未被捕获的 error 可以明确找到真实发生的代码位置就行。

    如果你的信息返回格式是碎片化的,那么还不如每个接口自行组织和返回信息。

    当然通常肯定都是部分状态可以统一处理,部分状态需要分别处理,那么只需要把适合统一处理的放到全局处理就好了。

    没有万能的设计,都是要根据项目当前的需求特点和未来可能的需求来选择采取哪种设计方式。
    wuwukai007
        14
    wuwukai007  
       257 天前
    接口里调用了 N 个方法,在最后一个方法里 raise 异常直接返回前段,不要太舒服
    lsk569937453
        15
    lsk569937453  
       257 天前
    相当于讨论"微服务之间的 http 调用是否应该捕获所有异常,然后返回 http status 200,最后在 response body 里面返回异常码和异常信息。"

    正方和反方只能说各执一词吧。
    wangritian
        16
    wangritian  
       257 天前
    错误和异常确实要分开处理,比如异常应当越过多级调用直接到最上层,错误要调用层单独处理、错误是普通返回但异常要报警通知、异常返回给用户的信息要脱敏或者简单替换为系统繁忙,等等
    很多人嘲笑 go 的 if err ,我认为这是正确处理错误和异常无法避免的操作
    Oktfolio
        17
    Oktfolio  
       257 天前
    这个说法确实没有问题

    不过,在业务代码比较复杂的情况下,抛出异常而不是使用统一返回会让代码更简单易读
    sprite82
        18
    sprite82  
       257 天前
    如果层级不深,或者这个错误很少出现,使用抛异常方式会简单很多。像某些参数校验接口,错误次数一多,内存占用能翻倍,很容易就会 OOM
    xloger
        19
    xloger  
       257 天前
    身为一名 Java 或者说 Kotlin 用户,我的观念是这样的:
    从需求本质看,我们需要的是对一个函数能清晰地得到它的正确状态下的返回值,和可能的失败情况。

    那么,Java 的 try catch 是一个比较好的方案,它能不影响正确状态的返回值,并且错误状态能携带额外信息。

    而另一种传统的错误码形式,它的返回更冗余,并且还需要对着看,想附加额外的错误信息并不那么方便。简而言之,表达力不够强。

    嗯,所以我认为 Result 是最理想最兼顾的方案。关于这点的讨论可以参考: https://www.zhihu.com/question/330263279
    mdn
        20
    mdn  
       257 天前
    理由太牵强,Nodejs 也可以这样使用,主要是风格/习惯问题

    Nodejs 可以使用 https://github.com/jshttp/http-errors
    xiaoHuaJia
        21
    xiaoHuaJia  
       257 天前
    其它我不知道,我一直这么写爽是真的爽。全局捕获就完事了
    xubeiyou
        22
    xubeiyou  
       257 天前
    都这么处理的吧 底层框架很多也这么写的
    Aresxue
        23
    Aresxue  
       257 天前
    try catch 确实会会增加一些开销,主要是在 java.lang.Throwable#fillInStackTrace()中会去爬取堆栈,但参数校验这个场景下不用纠结—抛异常是综合起来性价比最高的方式,jdk 其实有 java.lang.Throwable#Throwable(java.lang.String, java.lang.Throwable, boolean, boolean)这样一个构造器去构造不需要爬栈的异常(部分场景下只依赖异常类型而不关心堆栈),但不知道为什么并没有开放出来,后续如果能开放出来搭配这个场景应该是最优解。
    shawnsh
        24
    shawnsh  
       257 天前 via Android
    try catch 可能不是性能洼地
    iOCZ
        25
    iOCZ  
       257 天前
    据我所知 try catch 的代码在指令层面每执行一条就要去检查状态寄存器异常标志位是否被设置。我觉得这个开销其实还好。
    itechnology
        26
    itechnology  
       257 天前
    我感觉这两个理由实在是太牵强了。我们公司就是“使用抛异常的方式返回校验不通过的结果”,自定义了一个 businessException ,入参是错误码,由全局异常处理来根据错误码返回对应的错误信息给用户。
    lesismal
        27
    lesismal  
       257 天前   ❤️ 1
    明明是 golang 的 if err 更适合错误处理、鲁棒性,一帮习惯了 java 的人喷 golang if err 。
    aguesuka
        28
    aguesuka  
       256 天前
    好歹换成 Haskell 吧, 21 世纪了还在用 sum type 代替 product type
    naivety
        29
    naivety  
       256 天前
    好用,但是如果属于经常触发,还是建议有替代方案
    IvanLi127
        30
    IvanLi127  
       254 天前
    后端处理不了用户请求,可不就是遇到了异常情况。很多表单验证的库,验证不通过也是抛异常出来的。当然他们也有可选用 boolean 来标记是否通过验证。
    性能问题基本可以忽略不计吧。如果是牺牲可读性来换这点性能,那咋还用 js 呢,不得换语言先。
    我认为抛异常还是手动判断只是风格问题,他说的理由我感觉就是在扯淡。
    thynson
        31
    thynson  
       250 天前
    我是主张用异常的。
    如果为了性能,自定义的业务异常类可以避免捕获调用栈,生成调用栈的性能开销是极大的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   961 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 19:27 · PVG 03:27 · LAX 12:27 · JFK 15:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.