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

后端 response code 该怎样返回?

  •  
  •   hlayk · 2021-10-18 18:42:01 +08:00 · 4863 次点击
    这是一个创建于 1129 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前提:前后端定义了通用的数据结构包含 data,mseeage,code,success 这几个基本字段用来去接收后端接口的数据。

    场景:某一接口客户端发出的请求出现参数或后端校验等业务错误

    问题:后端 http 层的 response code 应该返回什么? 200 还是非 200 ?(呆过的不同公司有着不一样的习惯)

    问题来源:主要是用的网络请求框架( retrofit ),对于小于 200 或者大于等于 300 的 response code 直接抛了异常,但我并不想对这异常再进行解析 HttpException 中的 response body 解析出上述的数据结构,所以我拦截了 response 改了 response code 为 200 。这样的话,我对于 response code 无论是什么,我都可以同样的对象解析。

    第 1 条附言  ·  2021-10-18 20:02:36 +08:00
    对于后端 response code 返回特定的 4xx 5xx 我是赞同的。只是不想对那种 非 200 的 response,在 catch 中做额外的解析。
    [代码示意]( https://s3.bmp.ovh/imgs/2021/10/776467738425d9c4.png)
    44 条回复    2021-10-21 11:19:07 +08:00
    kile
        1
    kile  
       2021-10-18 18:51:39 +08:00   ❤️ 3
    code 是业务码,是前后端进行约定的东西。不要用和 http code 一致的方式,这样会让人混淆。。
    Jooooooooo
        2
    Jooooooooo  
       2021-10-18 18:54:36 +08:00   ❤️ 4
    0 成功, 去拿 data 中的内容

    非 0 异常, 展示 msg 中的内容
    securityCoding
        3
    securityCoding  
       2021-10-18 18:58:08 +08:00
    success 没看懂 ,其他三个够用了
    SingeeKing
        4
    SingeeKing  
       2021-10-18 19:06:13 +08:00   ❤️ 1
    遵从 REST 的应该是 400,不遵从就随缘来。。
    CodeCodeStudy
        5
    CodeCodeStudy  
       2021-10-18 19:06:40 +08:00   ❤️ 1
    code,用 1 来表示成功,大于等于 1000 的整数表示错误码,之所以用 1 是因为弱类型语言中 1 == true,让人一眼就认为是表示肯定的意思,用 1000 以上的整数是为了避免和 http 状态码混淆
    b1t
        6
    b1t  
       2021-10-18 19:13:58 +08:00 via iPhone
    我今天也把代码里的大于 300 抛异常给注释掉了,等个讲解
    hingbong
        7
    hingbong  
       2021-10-18 19:37:06 +08:00 via Android   ❤️ 1
    我们是遵循 HTTP 定义,异常都是 4xx 5xx,当然,封装的结构也有详细的错误码
    jerryshao
        8
    jerryshao  
       2021-10-18 19:37:11 +08:00   ❤️ 1
    后端参数校验错误应返回 400 HTTP respond code 。
    message 应返回有帮助性的错误信息,比如请求参数里的 XXX 字段长度不能超过 YYY 等等。
    code 字段可以是自定义错误码,一个自定义错误码对应一个异常。

    Retrofit 抛异常是对的,前端应该 catch 这个异常并做相应处理。
    比如 catch 异常并分析 respond 是 400,打印日志,看是否需要提示前端用户参数错误或加强表单验证。
    如果 catch 异常并分析 respond 是 500,打印日志,上报监控指标,配置 client 进行请求重试。
    hlayk
        9
    hlayk  
    OP
       2021-10-18 19:43:42 +08:00
    @jerryshao 后端返回是没问题 retrofit 抛异常也对。只是后端对于正确与否的数据都是同样的封装 所以 retrofit
    将异常给抛出来需要做额外的解析 如果后端返回的是 200 自定义的数据结构 中 code 再指定的话 那样就不需要写额外代码了,我只需解析一次返回对象 针对不同业务 code 做不同的处理
    hlayk
        10
    hlayk  
    OP
       2021-10-18 20:05:12 +08:00
    @securityCoding code 太具体 不够抽象 大部分业务只关心成功 失败最多显示下 message
    Hyvi
        12
    Hyvi  
       2021-10-18 20:48:18 +08:00 via iPhone   ❤️ 1
    非 200 。以后监控更方便搞。自定义的 code 最好自定义的错误。
    IvanLi127
        13
    IvanLi127  
       2021-10-18 20:50:27 +08:00 via Android
    在 header 传递业务层的 code 。
    jerryshao
        14
    jerryshao  
       2021-10-18 21:24:53 +08:00   ❤️ 1
    @hlayk 可以是可以,但是大家在这里建议的是业界比较认可的做法。

    如果返回 200,前端根据 code 字段做相关处理,那后端做可用性相关的监控就比较让人头疼。
    不知道你们有没有对后端的 canary test,中文好像叫拨测?将来持续测试后端 api 的话,正常来说判断 api 是否成功就是使用这些 http respond code 。如果后端都是返回 200,那相关的测试也无法从 http respond code 获知是否成功,需要解析里面的自定义 code 才知道。
    hlayk
        15
    hlayk  
    OP
       2021-10-18 21:43:23 +08:00
    @jerryshao 是的 我认为后端这样返回是对的 只是我自己代码里加了个拦截器 把所有 response code 都改写成了 200 这样方便自己统一的处理 但是写完感觉怪怪的
    oxromantic
        16
    oxromantic  
       2021-10-18 22:21:56 +08:00   ❤️ 2
    想想 http 的 code 有啥作用就能想通怎样用最好

    举例来说,http 400 表示错误的请求,404 很多框架表示服务找不到不可达,这些都是属于预期之外的错误,在评估服务健康度的时候都需要采纳,如果混用,譬如把 404 作为常规业务逻辑(离谱点譬如搜索找不到就返回 404 ),就会产生很大的功能混淆,如果再集成一些网络日志框架(听 X 之类),简直就是业务和标准错误混合的灾难

    可以参考下百度云 api 的设计,虽然百度云很流氓,但是不可否认 api 定义还是有参考价值的

    另外我不同意上面说的持续测试只采用 http response code 来判断,这种属于没经历过 http 时代电信的鞭打以及没用过 cdn,永远不要相信 http response code 能代表你业务的状态,否则就是给项目埋雷
    tiedan
        17
    tiedan  
       2021-10-18 23:09:34 +08:00
    code 返回 200,code 用特定错误代码,网关层写规则根据 code 转换成 4xx or 5xx
    xuanbg
        18
    xuanbg  
       2021-10-19 07:24:01 +08:00
    实际上有 success 表示调用是否成功的话,code 基本没啥用。因为你 success 是 false,都直接输出 message 了。有 code 啥事?
    xuanbg
        19
    xuanbg  
       2021-10-19 07:28:10 +08:00
    @oxromantic 对的,http response code 只能代表 API 服务本身的状态,而不能代表 API 服务上的业务的状态。把这两个状态混起来用虽然也能用,但遇到问题就很难定位到底是哪个层面的问题了。
    yidinghe
        20
    yidinghe  
       2021-10-19 08:04:56 +08:00 via Android
    协议层的问题和业务层的问题不要混淆吧,不然的话例如前端得到 404,可能是后端框架因为配置错误根本没将请求转发给业务层,会给排查带来不便
    Rache1
        21
    Rache1  
       2021-10-19 09:27:37 +08:00
    看前端,可以让前端传个指定 header 来给所有响应都返回 200,默认按照 HTTP CODE 返回。

    实际 response 里面的 code,我之前的做法都是三位 HTTP CODE + 三位业务 CODE 。 比如 400001,400 就是对应 HTTP CODE 中的请求参数有问题,001 就是可能是某个字段或者某个过程没有校验通过。
    2i2Re2PLMaDnghL
        22
    2i2Re2PLMaDnghL  
       2021-10-19 10:19:56 +08:00   ❤️ 1
    作为 Web 实质标准的 JavaScript,其 Fetch API 对于 4xx 5xx 都不抛错,你换个正常点的请求框架吧。

    有人说,并不一定非得用 HTTP status code 才叫 RESTful,甚至不一定需要 HTTP

    另外,我不推荐 "success": true/false,而采用 "status": "OK"/"NOT_FOUND"/... ,这样塞更多的实质状态比较方便。
    不要用「码」,用「符号」。码是在计算机性能不足的情况下的妥协,符号才是正统。

    @yidinghe 这个问题本应当可以快速地从 404 text/html 还是 404 application/json 区分出来
    oxromantic
        23
    oxromantic  
       2021-10-19 11:05:41 +08:00
    @2i2Re2PLMaDnghL retrofit 你居然让换个正常点的框架?类似 ios 的 alamofire,都是 top1 的框架,都不建议在非 200 的 http status code 里处理业务逻辑
    hlayk
        24
    hlayk  
    OP
       2021-10-19 11:23:52 +08:00
    @oxromantic 大家又不是都是搞移动端的 不知道这些库也正常
    abcbuzhiming
        25
    abcbuzhiming  
       2021-10-19 11:40:44 +08:00
    关于 code 返回什么,一直有争议,有人认为就应该用 http 的 status code,所以他们返回 200 ;而另外一群人比如我就认为 code 是业务码,和 http status 无关,正常下就是 0,非 0 就是错误,并且附带错误信息 msg 。
    lewinlan
        26
    lewinlan  
       2021-10-19 12:55:17 +08:00 via Android
    业务内的异常就装在 code 里,http 给 200 。
    网络,框架等非业务的异常,才用 400/500 的 http 。

    把资源装进 data,这个事情就已经不 REST 了
    2i2Re2PLMaDnghL
        27
    2i2Re2PLMaDnghL  
       2021-10-19 13:01:28 +08:00
    @oxromantic 这个建议是为了 HTTP 以外的一些协议没有 status code 所以将 HTTP 降级。这就好比因为很多网站不支持 bbcode 就要求现在在用 bbcode 的网站一律不允许使用 bbcode 一样可笑。
    oxromantic
        28
    oxromantic  
       2021-10-19 13:46:39 +08:00
    @2i2Re2PLMaDnghL 你搞错了,这些 status code 并不是你应用独占的,和容器抢这些 status code,就会给前端引入不确定性的混乱,而没有个前端定义一个可以直接判断属于业务数据的基础规则
    2i2Re2PLMaDnghL
        29
    2i2Re2PLMaDnghL  
       2021-10-19 14:26:06 +08:00
    @oxromantic 那就更诡异了,容器为什么要抢 status code ?它连 HTTP 都不 aware
    penll
        30
    penll  
       2021-10-19 14:30:42 +08:00
    code 直接英文字母,方便后端定位问题。
    message 只是给用户看得友好信息
    oxromantic
        31
    oxromantic  
       2021-10-19 16:04:21 +08:00
    @2i2Re2PLMaDnghL pcf/k8s 都会啊,可以了解下
    unco020511
        32
    unco020511  
       2021-10-19 16:45:27 +08:00
    两种都可以,看你们怎么理解,可以把 http 单纯当做一个数据传输协议,只要数据传输成功一律 httpcode200,然后定义自己的业务 code.同时因为 httpcode 也是语义化的,也可以使用仅使用 httpcode 一套来表示传输及业务状态
    ychost
        33
    ychost  
       2021-10-19 17:50:52 +08:00
    code 建议用字符串,这样方便两个调试,httpCode 一律 200
    2i2Re2PLMaDnghL
        34
    2i2Re2PLMaDnghL  
       2021-10-20 09:40:23 +08:00
    @oxromantic 首先,PCF 似乎是 VMWare 的多个不同的东西的品牌名称?具体没搜到。k8s 是编排工具而不是容器。
    其次,各类 load balancer 看上去也并不会抢 status code,而是尝试中间捕获 status code 来判断服务健康状况来安排重启和替换请求,这种情况下会修改的可不止是 status code,而是整个响应都会被替换。
    xingheng
        35
    xingheng  
       2021-10-20 13:27:32 +08:00
    @Jooooooooo #2 我要是看见谁用 0 标识自定义 code 为成功的话一定往死里骂,int 的默认值(在很多语言里很多都)是 0,本来就是取个 int 的事情非要我区分到底是因为服务器本身返回的傻逼 0 还是 code 值取不到用了 int 默认值。
    oxromantic
        36
    oxromantic  
       2021-10-20 13:55:27 +08:00
    @2i2Re2PLMaDnghL pcf 是比较早的商业容器实现,大概被 vmware 收购了,具体没了解,既然你提到整个响应都会被替换,这就是我之前描述的场景,你以为的业务 response,实际已经被替换了,所以不能光靠 http status code 来处理业务,还需要加额外的逻辑,但既然加额外的逻辑,何必还抱死 http status code ;另外,我所谓的容器是广义的,譬如远古的 war 跑在 tomcat 里,那么 tomcat 就是 war 的容器,tomcat 自己也会用到 http status code 表达自己的状态
    Jooooooooo
        37
    Jooooooooo  
       2021-10-20 14:45:16 +08:00
    @xingheng 你担忧的问题在这里不是问题. 用了就知道.
    2i2Re2PLMaDnghL
        38
    2i2Re2PLMaDnghL  
       2021-10-20 15:42:22 +08:00
    @oxromantic 替换应是对前端透明的,不需要额外逻辑。
    Tomcat 算是混合了一个编排工具?
    编排工具如何返回它自身的信息应当是可以自定义的,而不是埋暗雷(但暗雷见得多了,Flask 也暗雷)。不过现在问题是科技树还没点到动态编译语言。

    当然,如 #26,放 data 已经不 REST 了,本来的处理上就是 body 就是全部内容或者没有内容,甚至,尽管不那么典型,这个 URL 逻辑上是可以 cd 进去的(类似 WebDAV )。
    应当将这种状态和其他协议的 code/data 状态进行对应。gemini 更诡异一点(
    xingheng
        39
    xingheng  
       2021-10-20 16:34:24 +08:00
    @Jooooooooo #37 不是所有语言都支持 optional type,后端写的接口需要考虑各种语言的使用场景。
    bthulu
        40
    bthulu  
       2021-10-20 17:11:09 +08:00
    非对外公开给其他部门或其他公司使用的 API,一律不做任何处理,什么 status, code, msg 都不需要,逻辑成功就返回对象,失败就返回异常信息。前端框架统一对 4XX 错误做下处理,其余什么也不要做。简单就是美
    zachlhb
        41
    zachlhb  
       2021-10-21 08:10:26 +08:00 via iPhone   ❤️ 1
    http code 永远返 200,然后错误码用自己数据的 code 区分,为什么不用 http code,因为一些前端框架拿不到非 200 的响应数据,非 200 响应在前端来看就是异常,直接走前端框架的异常处理了
    bug123
        42
    bug123  
       2021-10-21 08:11:13 +08:00
    0 表示成功
    非 0 表示错误码,message 作为额外的补充
    hlayk
        43
    hlayk  
    OP
       2021-10-21 09:21:42 +08:00
    @zachlhb 是的 问题就在这里 返回的响应结果本身就是同一个数据结构 但是因为 http code 非 200 导致框架抛出异常 我这里就需要额外捕获异常 再从异常中解析 response 这在我这里看来就是多此一举 但是我也没有合适的理由去说服后端去改 http code 所以加了拦截器 将后端所有的 http code 改为了 200 以便统一处理
    flyingfz
        44
    flyingfz  
       2021-10-21 11:19:07 +08:00
    http 协议相关 的状态码, 交给 status code . 例如 无权限 403, 找不到资源 404,参数错误 400 之类.

    业务的状态码交给 code, 例如登陆失败, 扣款失败。注意, 此时 status code = 200 .
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3098 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 14:34 · PVG 22:34 · LAX 06:34 · JFK 09:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.