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

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

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

    比如有一个查询车辆详情的接口,参数定义的是车牌号,但是我做接口测试可能会传入纯数字、英文、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
    当然是捕捉参数异常丢出去,你同事那直接就是懒得处理
    liprais
        3
    liprais  
       2022-12-26 11:27:07 +08:00
    直接报 java 错误是抛异常?
    抛异常说明有问题,用户不应该看到你内部的异常
    cai88112
        4
    cai88112  
       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 。
    yatoooon
        9
    yatoooon  
       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
    感觉应该区分「输入 /输出数据不合法」和「程序内部状态错误」吧。

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

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

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

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

    至于随地抛异常,我是反对的,因为异常意味着程序状态发生了不正常的情况,即使可以在上层捕获,这种用法给人的感觉就像用异常处理 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   ·   我们的愿景   ·   实用小工具   ·   2479 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 05:14 · PVG 13:14 · LAX 21:14 · JFK 00:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.