请教一下,你们写接口的时候如果传入参数不合法,返回的结果是直接提示参数非法还是报错? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
InHello
V2EX    程序员

请教一下,你们写接口的时候如果传入参数不合法,返回的结果是直接提示参数非法还是报错?

  •  
  •   InHello 2022-12-26 11:22:09 +08:00 6831 次点击
    这是一个创建于 1041 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如有一个查询车辆详情的接口,参数定义的是车牌号,但是我做接口测试可能会传入纯数字、英文、null 等等这些正常参数外的其他字符。 我司返回来的结果直接报 java 错误,在我的理解中如果参数非法,返回的接口应该是提示用户"参数非法"而不是直接报一个 java 错误,不知道对不对。

    54 条回复    2022-12-29 16:00:14 +08:00
    nekoneko
        1
    nekoneko  
       2022-12-26 11:26:30 +08:00
    对, 让后端统一处理一下返回信息
    JYii
        2
    JYii  
       2022-12-26 11:27:00 +08:00   1
    当然是捕捉参数异常丢出去,你同事那直接就是懒得处理
    F281M6Dh8DXpD1g2
        3
    F281M6Dh8DXpD1g2  
       2022-12-26 11:27:07 +08:00
    直接报 java 错误是抛异常?
    抛异常说明有问题,用户不应该看到你内部的异常
    mixtbkig
        4
    mixtbkig  
       2022-12-26 11:27:08 +08:00
    你是对的
    InDom
        5
    InDom  
       2022-12-26 11:27:23 +08:00
    报错误一般就是真的没在入口做检测, 后面莫名其妙在某个地方没按预期运行崩了.
    不过入口参数检查的时候,如果不符合预期也可以使用报错的方式反馈.

    但是这两种还是可以分出来的 如果 每次都完全不同的错误就属于前者, 如果每次错误提示都很相似, 大概率是第二个了.
    k9982874
        6
    k9982874  
       2022-12-26 11:28:06 +08:00
    直接爆堆栈就过分了,让后端加 validation
    InHello
        7
    InHello  
    OP
       2022-12-26 11:29:08 +08:00
    @liprais 抛异常的
    wolfie
        8
    wolfie  
       2022-12-26 11:29:26 +08:00
    序列化错误怎么算?
    int32 类型,传 abc 。
    kaixinyidian
        9
    kaixinyidian  
       2022-12-26 11:29:40 +08:00
    后端统一处理
    wong2
        10
    wong2  
       2022-12-26 11:29:58 +08:00
    400 而非 500
    InDom
        11
    InDom  
       2022-12-26 11:30:53 +08:00
    但是 如果是后者 属于 预期内的错误, 是可以以可以预期的方式提供错误信息(比如按照接口规范返回与前端沟通过的特定格式的数据)

    而非直接给了一个前端不曾预料的返回内容, 所以,不管怎样,如果出现了这个不可预期的返回,就是后端的锅.
    InHello
        12
    InHello  
    OP
       2022-12-26 11:31:51 +08:00
    @wong2 code 直接报 500 ,message 报异常
    dd991
        13
    dd991  
       2022-12-26 11:37:12 +08:00
    后端提示什么,直接展示出来就好,老板会让他改的
    unco020511
        14
    unco020511  
       2022-12-26 11:40:10 +08:00
    后端有框架可以很方便的校验参数有效性
    AirBai2
        15
    AirBai2  
       2022-12-26 11:43:31 +08:00
    http 状态码 400 ,外加 message
    wangritian
        16
    wangritian  
       2022-12-26 11:46:22 +08:00
    你是指报异常吗?确实不对,应该报业务或框架层级的错误
    bthulu
        17
    bthulu  
       2022-12-26 11:52:56 +08:00
    我一般是报 200, 数据返回默认值
    lucays
        18
    lucays  
       2022-12-26 12:00:51 +08:00
    总之报 500 肯定是有问题
    200 还是 4xx 看公司内部规范。。。
    wu00
        19
    wu00  
       2022-12-26 12:02:26 +08:00
    参数错误,后端 validation+默认提示(给开发人员看的),前端自己也要做前端的 validation ,用户提示信息是前端自己定
    业务错误,http 状态码 4xx ,给 errorType 和 message(给开发人员看的),前端根据 errorType 做页面逻辑和错误提示
    服务端异常,http 状态码 500 ,前端给友好页面 /提示(稍后再试)
    buchikoma
        20
    buchikoma  
       2022-12-26 12:04:24 +08:00
    这种需要前后端定一下异常类型和异常提示,后端根据异常类型抛错误信息和 code ,前端根据 code 对错误信息进行包装抛给用户
    xuanbg
        21
    xuanbg  
       2022-12-26 12:49:22 +08:00
    直接抛异常那就是懒。嗯嗯,虽然我有时候也这样。
    spring 是可以在实体类的字段上通过注解来对参数进行校验的。如果不是实体类,那也可以自己写校验逻辑。然后抛参数非法的异常出去就好了。

    虽然,这样做意义其实也不是很大。但作为一个有追求的程序员,优雅是必须的。
    Felldeadbird
        22
    Felldeadbird  
       2022-12-26 13:32:32 +08:00
    按理来说应该提示非法参数。 估计后端没做处理,当非法提交后涉及到异常报错了,触发了 java 错误。

    前端的做法应该是根据 code 或者 status 返回结果 执行对应的提示页或错误页。
    hhjswf
        23
    hhjswf  
       2022-12-26 14:19:32 +08:00
    说明没有做全局异常处理。
    zypy333
        24
    zypy333  
       2022-12-26 14:19:44 +08:00
    我想起来我的奇葩同事,写个传入楼层返回该楼层门禁点位 list ,然后他硬是写了个如果查不到数据手动抛个异常,但是实际上有的楼层确实是没有门禁报警器的,然后他还不愿意改,最后是前台想办法单独处理,遇到那个楼层,直接不请求后台
    zypy333
        25
    zypy333  
       2022-12-26 14:30:50 +08:00
    他应该不上 v 站

    ```java
    public TableDataInfo list(@PathVariable String floor) throws Exception {
    EntrancePoint entrancePoint=new EntrancePoint();
    List<PublicEquipment> listOfep=new ArrayList<>();
    List<EntrancePoint> list=null;
    if(floor.isEmpty()){
    throw new Exception("Please enter the number of floors");
    }else {
    entrancePoint.setFloor(floor);
    list = entrancePointService.selectEntrancePointList(entrancePoint);
    if(list.isEmpty()){
    throw new Exception("The set or list cannot be empty!");
    }else{
    for (EntrancePoint entrancePoints:list) {
    PublicEquipment pe =new PublicEquipment();
    pe.setDeviceName(entrancePoints.getName());
    pe.setIp(entrancePoints.getEntranceHost());
    pe.setModelName(entrancePoints.getModelName());
    pe.setState(entrancePoints.getEntranceStatus().equals("0")?"开启":"关闭");
    pe.setDoorNum(entrancePoints.getVariable());
    listOfep.add(pe);
    }
    }
    }
    return getDataTable(listOfep);
    }
    ```
    kop1989smurf
        26
    kop1989smurf  
       2022-12-26 14:34:49 +08:00
    不能任凭异常抛出。

    1 、异常需要全局处理,要有对应的类型编号、唯一编号、日志记录。
    2 、未处理的异常会增大 web 容器的开销。
    3 、不利于其他产品进行统一的错误提示。
    InHello
        27
    InHello  
    OP
       2022-12-26 14:41:15 +08:00
    @Felldeadbird 对的 就是这样的,但是前端也没有做任何异常处理
    InHello
        28
    InHello  
    OP
       2022-12-26 14:41:58 +08:00
    @zypy333 就是这种
    InHello
        29
    InHello  
    OP
       2022-12-26 14:42:40 +08:00
    @kop1989smurf 我感觉我司他们就没有做任何处理
    YouTing
        30
    YouTing  
       2022-12-26 15:30:00 +08:00
    前后端都没有写校验,也没有抛出异常。前端至少要对 500 等未知错误进行提示,因为不知道什么时候就出奇奇怪怪的的问题,有提示用户就知道这一步不能干,后端的参数校验是必写的
    zoharSoul
        31
    zoharSoul  
       2022-12-26 15:32:19 +08:00
    如果用户正常操作不会碰见的 case, 那什么文案无所谓的
    Macolor21
        32
    Macolor21  
       2022-12-26 16:00:18 +08:00
    spring validation 这么难学吗?
    chioplkijhman
        33
    chioplkijhman  
       2022-12-26 16:20:15 +08:00
    422 Unprocessable Entity
    libook
        34
    libook  
       2022-12-26 16:42:58 +08:00
    直接包 Java 错误是不是意味着根本没做错误处理?

    具体还是得形成标准,而标准不唯一。主要的目的还是利于联调以及前端进行错误展示,比如对所有的情况划分业务状态码。
    ThreeK
        35
    ThreeK  
       2022-12-26 17:14:42 +08:00
    Validation 加 Exception Handling 。自己代码直接参数异常抛出去,项目统一拦截返回,每块代码都各司其职。
    msg7086
        36
    msg7086  
       2022-12-26 17:40:08 +08:00
    抛异常可以但是最顶层要接住异常然后返回正确的 JSON/XML 主体啊。
    zsj1029
        37
    zsj1029  
       2022-12-26 18:52:08 +08:00
    @zypy333 我也会这样写,这个习惯个人来看挺好的,但是全局必须有个 catch 拦截,转可读格式数据给前端,我说的是接口的情况。如果是 sdk 调用,调用方处理异常也是可以接受的
    devswork
        38
    devswork  
       2022-12-26 20:41:25 +08:00
    @NotBlank("车牌不能为空值")
    @Pattern(regexp = "正则",message = "车牌格式不合法")
    @Length(min = 7,max = 7,message="车牌必须为 7 位")
    private String number;
    devswork
        39
    devswork  
       2022-12-26 20:44:25 +08:00
    @devswork 我们每个接口都得定义入参 VO ,以及出参 VO ,然后每个 VO 上的每个参数都要加 validation 判断 null 、判断空字符串、判断长度等,必要时候加正则校验,然后写一个统一异常处理器,处理 BindException 、MethodArgumentNotValidException 、ConstraintViolationException ,如果异常是属于业务上定义的,自己封装一个 Exception 和定义一个返回码,用来表示数据不符合业务规定。
    FawkesV
        40
    FawkesV  
       2022-12-26 20:47:12 +08:00
    @devswork #38 正规做法就这样, 对入参进行校验就好
    Seayon
        41
    Seayon  
       2022-12-26 22:28:33 +08:00
    基于 Spring 和 Hibernate Validation 的全局参数统一校验,Spring Boot 参数校验
    https://blog.csdn.net/Seayonzhao/article/details/118419116
    nanjingwuyanzu
        42
    nanjingwuyanzu  
       2022-12-26 23:05:11 +08:00 via iPhone
    后端这也太懒了吧
    aru
        43
    aru  
       2022-12-27 07:53:20 +08:00
    @devswork 我就说一句,新能源车牌是 8 位
    netabare
        44
    netabare  
       2022-12-27 08:29:29 +08:00 via Android   1
    感觉应该区分「输入 /输出数据不合法」和「程序内部状态错误」吧。

    在我的理解里,一个程序应该是只对特定的输入有效,产生期待中的输出,对于这以外的其他输入,应该直接拒绝运行,避免产生意想不到的结果。

    在后端里面,这个逻辑应该可以等价于……一个大的事件循环在监听外部的请求,首先检测请求的有效性,对于有效的请求,开始执行这个程序(启动线程、调用服务之类的),
    netabare
        45
    netabare  
       2022-12-27 08:33:03 +08:00 via Android   1
    如果请求内容无效,直接返回错误报告。

    然后…在后端程序里面,毕竟无法保证程序状态永远正确,所以需要用异常来检查和保证程序尽量正确运行。

    唔,我倒是没怎么写过后端,但是我对程序的理解是这样。感觉重要的还是如何保证请求的内容健康有效这一个环节,当然可用的工具也很多就是了。

    至于随地抛异常,我是反对的,因为异常意味着程序状态发生了不正常的情况,即使可以在上层捕获,这种用法给人的感觉就像用异常处理 NPE 一样(
    dengji85
        46
    dengji85  
       2022-12-27 08:59:19 +08:00
    我就不做后端校验的,只做前端校验,因为时间不够,能用就行
    wupher
        47
    wupher  
       2022-12-27 10:41:11 +08:00
    你的理解没错。

    后端永远不应依赖于前端校验。正则表达式校验一下车牌号,如果不会写,还可以询问 ChatGpt 。

    像这样写代码,能用。但一旦到了运营环境中,出现故障想要溯源,日志中到处都是异常栈,会很难追溯。
    shm7
        48
    shm7  
       2022-12-27 10:45:24 +08:00
    抛出特定类型的参数非法错误,外部错误处理机制返回 参数非法提示信息。
    daliusu
        49
    daliusu  
       2022-12-27 11:07:59 +08:00
    肯定也不能直接抛出内部错误
    可以约定抛出一个 400 错误,携带一个 errorMsg:"xxxx",然后再带个参数来描述需不需要前端弹出提示,比如 talkError:true ,这样前端在接口响应层直接拦截就可以自己写错误提示样式,具体错误信息后端返回,框架一般都自带这种功能
    devswork
        50
    devswork  
       2022-12-27 16:45:34 +08:00
    @aru 只是 validation 用法举个例子,不要在意细节
    zypy333
        51
    zypy333  
       2022-12-27 20:03:01 +08:00
    @zsj1029 我不理解这种写法居然还能有人赞同,数据库查不到结果就返回空就行了,抛个错是几个意思
    hellojukay
        52
    hellojukay  
       2022-12-28 14:24:00 +08:00
    直接返回 4xx , 但是不要直接提示 "xxx 参数不合法“,对于系统入侵者来说,这样的提示是一个指示牌,告诉他们怎么入侵系统。
    ma836323493
        53
    ma836323493  
       2022-12-28 15:47:22 +08:00
    前端都不做校验我后端做什么校验
    SACKJJKLL
        54
    SACKJJKLL  
       2022-12-29 16:00:14 +08:00
    参数后端校验,后端写个 wrapper 抛出或者直接 java 抛异常
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2351 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 10:41 PVG 18:41 LAX 03:41 JFK 06:41
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86