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

请问给 App 开发后端时,错误码应该使用 Http 状态码,还是放到返回的 json 里?

  •  2
     
  •   zhbzhbzhbz · 2021-12-25 00:27:53 +08:00 · 7559 次点击
    这是一个创建于 845 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如题,我知道是一个老生常谈的问题了,也翻了下 V2EX 上的帖子。 App 是那种经典的资料 /博客类 App 。 主要是想知道 [现在一般国内主流] 是怎么做的?就是比如给 Android 和 IOS 开发的话。 比如最基本的用户名已存在啊,用户名格式不对啊,如果按照传统 RESTAPI 的话应该放到 http 状态码里,但是一旦错误类型多起来就得自定义

    69 条回复    2022-01-15 17:06:31 +08:00
    misaka19000
        1
    misaka19000  
       2021-12-25 00:30:59 +08:00
    状态码表示 HTTP 状态,业务错误当然是放在返回 body 里
    sutra
        2
    sutra  
       2021-12-25 00:33:53 +08:00
    国内主流好像是放在 body 里。国外主流则似乎不同。
    zhbzhbzhbz
        3
    zhbzhbzhbz  
    OP
       2021-12-25 00:34:20 +08:00   ❤️ 1
    @sutra 确实好像是如此~
    rekulas
        4
    rekulas  
       2021-12-25 00:34:31 +08:00   ❤️ 2
    我赞成放 body ,发现国外有些大平台都把错误码体现在 http 感觉有点不可思议,网关错误跟程序错误傻傻分不清
    PerFectTime
        5
    PerFectTime  
       2021-12-25 00:41:34 +08:00   ❤️ 1
    个人做法是业务错误放 body ,数据不存在 404/token 过期 401/服务端异常 500 放 http
    lff0305
        6
    lff0305  
       2021-12-25 00:46:26 +08:00 via Android   ❤️ 3
    支持 body 。body 里的状态码能说明请求真正到达服务了。要按照 rest 的要求某个东西没找到返回 404 的话,说不清到底是业务的 404 ,还是到达业务前一大串的负载均衡反向代理 k8s/istio 网关各种 sidecar 的问题
    ssynhtn
        7
    ssynhtn  
       2021-12-25 00:59:58 +08:00 via Android
    HTTP 状态码根本就不够用
    zhbzhbzhbz
        8
    zhbzhbzhbz  
    OP
       2021-12-25 01:10:12 +08:00
    @lff0305 感谢~~~!经验之谈
    panlatent
        9
    panlatent  
       2021-12-25 01:32:01 +08:00 via iPhone   ❤️ 1
    REST 中使用状态码不代表着业务可以偷懒不反回业务错误码,使用状态码可以很好利用 http 工具 中间件 客户端 的一些功能和特性 。
    AdmiralDollBug
        10
    AdmiralDollBug  
       2021-12-25 01:47:12 +08:00   ❤️ 1
    业务错误和非业务错误最好要有比较清晰的边界,所以业务错误放 body ,非业务错误放 status code
    CEBBCAT
        11
    CEBBCAT  
       2021-12-25 02:18:53 +08:00   ❤️ 13
    都放。错误请求 4xx ,DB 挂了 5xx ,请求本身有问题比如操作用户没有的资源时视情况返回 403 、404 、400 等。HTTP 状态码便于监控服务状态

    放在 Body 里是为了区分不同的错误情况

    举例子来说,网络调试时点开一个 200 OK 的响应结果打开一看是个 404 的 JSON ,我简直他奶奶个腿儿

    P.S. 工作中发现不懂 HTTP 的人不在少数,这可能也是 200 OK 大行天下的原因之一
    Zhuzhuchenyan
        12
    Zhuzhuchenyan  
       2021-12-25 02:21:48 +08:00   ❤️ 1
    这个问题我们之前和团队里的朋友也有一个激烈的讨论,讨论的焦点就在于,
    给定一个这样的路由,/book/{bookID},当 bookID 不存在的时候,是直接给一个 404 还是返回 200 用 Body 中的一个自断来传递错误信息。
    我个人理解后面的那种做法,借楼问一下大家,
    - 这时候给 200 返回值总感觉有点奇怪,是否给 400 会更好一些?
    - 如果错误时返回一个特殊结构的 Body ,是否有必要在正常返回的时候也额外包装一层,比如说{error:null, ressource: T} ?
    DOLLOR
        13
    DOLLOR  
       2021-12-25 02:32:08 +08:00   ❤️ 4
    自从所有的业务异常都用 200 后,绝大多数非 200 的异常都是运维的锅。

    从此前端和后端就不用大半夜陪运维排查本应属于运维的故障了。
    Rocketer
        14
    Rocketer  
       2021-12-25 02:58:45 +08:00 via iPhone   ❤️ 3
    这有啥可争的?非 200 的 http code 也可以返回 body 啊。http 该错就错,body 里附加内部定义的错误码和信息就行了。
    CEBBCAT
        15
    CEBBCAT  
       2021-12-25 03:36:48 +08:00 via Android
    @DOLLOR 老兄,我想请问一下你们怎么做业务健康状态监控的呢?比如说各地的客户端频繁请求一个不存在的资源,或者 DAO 有问题
    whincwu
        16
    whincwu  
       2021-12-25 08:46:29 +08:00 via Android
    赞同 @CEBBCAT 的观点,放 body 不利于监控,很多工具都依赖 HTTP 头部,放 body 需要解码实体内容
    zed1018
        17
    zed1018  
       2021-12-25 08:53:08 +08:00   ❤️ 1
    放 http status ,不然人家协议设计一套这个是闲着蛋疼吗?只有 http status 无法描述具体错误的时候才会通过 400+body error 来描述
    chendy
        18
    chendy  
       2021-12-25 09:09:22 +08:00   ❤️ 1
    http 状态码 只区分错没错,是服务器错还是客户端错,简单区分 200 400 500 即可,直接用作错误码的话,遇到一些严格的 http 客户端 需要自己扩展状态码处理逻辑,比较麻烦
    需要特殊区分的错误编号,header 里单独放一个字段,body 里也放
    状态吗和 header 里的错误码 是方便各层代理统一处理
    body 里的错误码 是方便水平不一的客户端都能理解
    thtznet
        19
    thtznet  
       2021-12-25 09:12:17 +08:00   ❤️ 1
    这就是我讨厌 RESTAPI 的地方,无奈现在清一色的这种风格,客观得说,如果 API 设计合理,面向资源模式设计清晰的话,Http Status 的状态可以覆盖 90%的错误状态,很少存在业务错误需要把 code 放在 body 里的,如果业务错误非要放在 body 里说明 API 的设计没有完全面向资源,仍然以 action 的理念在设计 RESTful API ,但是实际情况是,一个需求非常非常难才能清晰地设计成资源模式,因为后端程序员长期接触面向对象设计思想,思维惯性在设计过程中自然而然会用面向对象的思路考虑 API 设计,不自觉的,我到现在还没法使用完完全全的 RESTful 。我感觉早期只编写 php 或者 asp 的程序员可能会相对容易点,我个人觉得对于后端来说,gRPC 才是接口风格设计的出路,不过现阶段并不方便,也不成熟,对测试也不友好,工具也不配套等等。
    lagoon
        20
    lagoon  
       2021-12-25 09:13:01 +08:00   ❤️ 1
    作为 app 开发者,作为一直从 body 拿的人,我觉得其实是应该放 Http 里。

    Http 的错误码设计出来,不就是干这个的吗?
    不要说区分这错误那错误,如果这种说法成立,拿 body 中也搞 n 个错误码好了,因为:xx 字段错误码代表 xx 类错误,yy 字段错误码代表 yy 类错误。

    合理吗?


    不过我建议,还是放 body 吧。
    对,和应该,不是一回事。

    你放 Http 里,大家还要适应一遍。
    讨论一遍,何苦呢?
    liaojl
        21
    liaojl  
       2021-12-25 09:15:39 +08:00 via iPhone   ❤️ 4
    这两个不冲突吧,发生错误时,http status 500 ,同时把业务的错误码放在 body 里。
    leafre
        22
    leafre  
       2021-12-25 09:43:26 +08:00
    http code 当然 http response ,business bode 放 result object to json
    mostkia
        23
    mostkia  
       2021-12-25 09:44:47 +08:00
    HTTP 状态码用来说明通讯问题,json 里放业务逻辑的状态码比较好,否则后期维护可能都不知道哪里出问题了。
    ZeroClover
        24
    ZeroClover  
       2021-12-25 10:02:33 +08:00
    RESTful 也不是 HTTP Status 里面放了错误码就不需要在 Body 里面返回具体错误原因了。这方面学习下 GitHub
    MrSheng
        25
    MrSheng  
       2021-12-25 10:21:39 +08:00
    个人支持放 body 里面,处理逻辑复杂度下降一个数量级
    zsdroid
        26
    zsdroid  
       2021-12-25 10:26:54 +08:00
    @zed1018 #17 世界上没有银弹,restful 又不是万能的。照你这么说,地球为什么要有这么多国家。直接一个地球国不就好了,战争也没了。
    wolfie
        27
    wolfie  
       2021-12-25 10:30:06 +08:00
    @lff0305 #5
    你说说什么场景会在业务上返回 404 ??
    wolfie
        28
    wolfie  
       2021-12-25 10:33:28 +08:00
    大多数业务错误场景,状态码肯定不能是 200 。
    比如字段校验错误,给 2xx 、还是 4xx 。

    https://s2.loli.net/2021/12/25/eEokV6wHMP8xdLB.jpg
    FrankFang128
        29
    FrankFang128  
       2021-12-25 10:37:50 +08:00
    请参考 GitHub API v3
    thinkershare
        30
    thinkershare  
       2021-12-25 10:46:34 +08:00
    HTTP 状态码放 HTTP 状态错误, 可以认为是服务器对状态的统一描述, 使用 401 表示 405 各种大类型的错误, 逻辑约束错误返回 403(body 中定义具体错误格式, 只在有错误的情况下 body 才返回错误结构的 json, 200 的时候直接返回调用的结果, 而不是总是包一层), 找不到返回 401, 没有错误 body. 如果实在想偷懒, 也可以简单粗暴, 全部返回 200, 然后总是套一层 Result 结果, 将主体结果内容放置到 data 中, 使用 code, message 等顶级属性描述服务器响应的正确性.
    yhxx
        31
    yhxx  
       2021-12-25 10:50:22 +08:00
    大多数业务错误场景,状态码一定要是 200 。
    HTTP 状态码给个 5XX 说明你的服务器炸了。
    已经能知道是业务错误,说明请求是正常接收到了的。
    learnshare
        32
    learnshare  
       2021-12-25 10:51:32 +08:00
    HTTP 状态码是基本信息,代表 HTTP 请求的状态,是有国际标准的
    业务逻辑当然是放到 body 里

    两个都要有,合理使用才是最有效的
    IvanLi127
        33
    IvanLi127  
       2021-12-25 10:59:37 +08:00
    两边都放。业务错误,HTTP 状态码 4xx ,具体错误代码放在 body 里。
    另外,HTTP 状态码是受服务内容影响的,不然要三位数的状态码干嘛。。。HTTP 能返回 404 ,难道是指 HTTP 服务器找不到吗?
    fkdog
        34
    fkdog  
       2021-12-25 11:35:39 +08:00   ❤️ 3
    一般来说都是结合 http status 和业务状态码一起用的。
    40x 系列表示这些请求已经进入到了应用内部处理,但是由于请求参数不对、权限不对、url 路径不对等原因应用内部返回了这些错误状态码。
    50x 系列表示 http 请求中间经过的某个网关发生了异常、超时,或者请求已经进入到了应用内部但是应用内部出现异常等原因。

    200 表示请求已经已经进入到了应用内部处理。至于业务里出现的一个错误码,比如余额不足、账号未实名认证啦这些,当然需要添加一个 code 表示异常错误来方便前端进行处理。

    其实业务 code 和 http status 也有重叠的地方。比如查找 id=1000 的 book ,https://xx.xx/detail?id=1000 ,你就会去纠结到底是 404 还是弄一个业务 code 。我自己的偏好是 404 只用于 url 在后端是否有对应的 RequestMapping ,对于根据某某参数、条件查不到某数据的这种情况我喜欢放到业务 code 里。这样的话 40x 、50x 系列的 http status 的功能就更偏向于运维监控层面而非业务相关。而且这样还有个好处就是内容传输协议不再局限于 http ,我可以随时调整协议格式,比如采用 grpc ,我不需要再去考虑迁移协议后怎么兼容原来 http 404 的问题,因为我的数据返回的业务 code 里已经涵盖了 http 404 的这种情况。

    前端这边肯定是先进行 http status 判断,然后再进行业务 code 判断。

    说到底还是因为 http status 这东西已经出现了几十年了,跟不上现在的互联网应用变化,所以国内的设计都是以实用角度出发,存粹把 http 协议当成是一个传输的载体。现在很多公司做的接口甚至都把 url 部分废弃掉了,需要访问哪个接口把服务名称写进 http 参数里交给后端做分发。

    github 早期的 url 是很 restful 的,后边规模大了,也开始不 restful 了。也就 V2EX 上一群没见过世面的小学生喜欢把 restful 挂嘴上。
    swcat
        35
    swcat  
       2021-12-25 12:32:54 +08:00
    放 http status 的是没受到过运营商的毒打, 有的运营商会拦截 404
    CEBBCAT
        36
    CEBBCAT  
       2021-12-25 12:54:33 +08:00 via Android
    @swcat 那个我很多年前碰到过,不过他们拦截 html 之外的 response 吗?
    swcat
        37
    swcat  
       2021-12-25 13:03:31 +08:00
    4,5 年遇到过的, 记不得响应是什么了
    icylogic
        38
    icylogic  
       2021-12-25 13:06:17 +08:00   ❤️ 2
    建议 V2EX 给这话题开个专用节点:错误码,想战的人可以每月战个痛,不想看的人就不看这个节点
    stardust21
        39
    stardust21  
       2021-12-25 14:24:50 +08:00
    按目前国内的情况,支持放 body 里面,状态码只用来区分非业务错误,例如 404 就是 url 拼错了,500 是服务器崩了。放 http code 的话一个 APP 对应多个后端服务的时候,同一个 http code 代表不同的业务错误的话,客户端怎么统一处理呢
    gy911201
        40
    gy911201  
       2021-12-25 14:31:15 +08:00
    @swcat 都快 2022 年了应该不太需要考虑运营商拦截了, 现在基本上都会去做全站 HTTPS 了, HTTPS 后运营商是拦截不到的.
    crece
        41
    crece  
       2021-12-25 14:40:47 +08:00
    http code 是 http 协议的一部分,做好通讯协议本身的事情就好,本就不应该和业务耦合在一起。
    pupboss
        42
    pupboss  
       2021-12-25 14:57:07 +08:00
    这么跟你说吧,绝大多数敲代码的没啥技术追求,200+错误码放 body 只是无奈之举。而在这种情况下,服务器如果真的 4xx 5xx ,他们写出来的应用基本都是不能正常处理的
    zhbzhbzhbz
        43
    zhbzhbzhbz  
    OP
       2021-12-25 16:06:14 +08:00
    @thtznet 确实
    zhbzhbzhbz
        44
    zhbzhbzhbz  
    OP
       2021-12-25 16:06:26 +08:00
    @chendy 感谢
    zhbzhbzhbz
        45
    zhbzhbzhbz  
    OP
       2021-12-25 16:06:33 +08:00
    @CEBBCAT 感谢
    eason1874
        46
    eason1874  
       2021-12-25 17:02:41 +08:00   ❤️ 2
    虽然 HTTP 是应用层协议,但国内主流是当成传输层协议来用

    HTTP 支持描述任何状态。比如,楼里挺多人说到的 404 ,HTTP 规范推荐用 Not Found 作为 404 短语,但并不强制。你有需求,你可以根据场景需求返回不同的 404 ,404 Service Not Found 、404 Page Not Found 、404 User Not Found ,甚至是 404 zhaobudao

    说句难听的,大多数码农懂个锤子 HTTP ,给他们解释明白的时间足够你写几百个 HTTP 网关过滤器了。投票解决,组里多数人都不懂 HTTP 应用特性那就不用
    xuanbg
        47
    xuanbg  
       2021-12-25 20:28:35 +08:00
    @whincwu 服务日志不分析不监控的么?
    zed1018
        48
    zed1018  
       2021-12-25 20:35:31 +08:00
    @zsdroid 所以你是看不懂还是看不全。http status 能表达的当然用协议定义。不能的 body 补充有什么问题吗
    xuanbg
        49
    xuanbg  
       2021-12-25 20:37:54 +08:00
    @eason1874 虽然 404 Service Not Found 、404 Page Not Found 、404 User Not Found ,甚至是 404 zhaobudao 。可以区分协议 /数据链路错误还是服务 /业务错误,但要让监控系统来自动区分就……哈哈哈,咱还是不折腾这个吧。既然把 http 当传输协议用了,那就让 http 的状态码只负责体现协议状态好了,业务状态就不乱入了吧。

    还有,所有的数据传输都是从应用层协议开始的,所以 http 协议是数据传输协议没错。并不是网络层协议才是数据传输协议。
    mmmfj
        50
    mmmfj  
       2021-12-25 20:59:50 +08:00
    赞成 body ,用以区分业务错误和协议错误,前端应用层也可以更好分开捕获两种情况
    jianguiqubaa
        51
    jianguiqubaa  
       2021-12-25 21:12:13 +08:00   ❤️ 3
    jianguiqubaa
        52
    jianguiqubaa  
       2021-12-25 21:12:42 +08:00
    才看到有人已经发过了。。
    beginor
        53
    beginor  
       2021-12-25 21:54:04 +08:00
    @jianguiqubaa 这个图好,http 200~299 有 100 个表示成功的代码,300 到 599 有 300 表示错误的代码, 说不够用的人的业务得多复杂呢?
    chairuosen
        54
    chairuosen  
       2021-12-25 22:04:30 +08:00
    这个问题又来了,轮回啊~~
    chairuosen
        55
    chairuosen  
       2021-12-25 22:11:34 +08:00   ❤️ 1
    结论:网关链路等非业务机错误放 httpcode ,业务机错误放 body 协议里。

    分析:
    前端需要处理两种错误:业务错误和链路错误,业务错误需要后续处理,链路错误直接抛异常。
    要么两种揉在一起通过一个字段判断,要么两种分开。
    揉在一起的话,httpcode 不够用,放 body 的话需要多种后台服务返回一样协议格式的东西,限制太大。
    那么就分开放错误码。
    我能看到的 body 一定是业务返回的,不用担心其他人的 body 格式解出问题。
    我能看到的 http error code 一定不是业务机返回的,看到了就说明请求没到业务,不用管 body 。
    CEBBCAT
        56
    CEBBCAT  
       2021-12-25 23:05:32 +08:00
    @beginor #52 老实说,HTTP 状态码有一个分配表,你要不先读一下那个

    https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
    xiaofan2
        57
    xiaofan2  
       2021-12-25 23:31:12 +08:00   ❤️ 2
    beginor
        58
    beginor  
       2021-12-25 23:57:39 +08:00 via Android
    @CEBBCAT 那么多未使用的状态码,拿来用就行了,再 body 中再搞一套又能有多大意义呢?
    FrankAdler
        59
    FrankAdler  
       2021-12-26 02:42:47 +08:00
    http status 全 200 ,错误码放 body 的起码有一个场景会出问题,就是监控,市面上常见的监控系统,基于 http staus 的全部会失效,很惨痛的教训。
    zhbzhbzhbz
        60
    zhbzhbzhbz  
    OP
       2021-12-26 03:42:16 +08:00
    @xiaofan2 感谢,大作
    Jackeriss
        61
    Jackeriss  
       2021-12-26 09:05:10 +08:00 via Android
    这个问题每年都有人问,记得上次看到还有还多人觉得都放 http 状态码好,现在意见逐渐统一了。
    kevinlq
        62
    kevinlq  
       2021-12-26 10:59:18 +08:00   ❤️ 1
    放在 Http 状态吗里面。

    前几天刚好看了某个大佬的文章,希望对你有帮助;

    左耳朵耗子:我做系统架构的一些原则 https://coolshell.cn/articles/21672.html

    下面是原文内容:

    最典型的例子就是 HTTP 调用的状态返回码。业内给你的标准是 200 表示成功,3xx 跳转,4xx 表示调用端出错,5xx 表示服务端出错,我实在是不明白为什么无论成功和失败大家都喜欢返回 200 ,然后在 body 里指出是否 error (前两年我在微信公众号里看到一个有一定名气的互联网老兵推荐使用无论正确还是出错都返回 200 的做法,我在后台再三确认后,我发现这样的架构师真是害人不浅)。这样做最大的问题是——监控系统将在一种低效的状态下工作。监控系统需要把所有的网络请求包打开后才知道是否是错误,而且完全不知道是调用端出错还是服务端出错,于是一些像重试或熔断这样的控制系统完全不知道怎么搞(如果是 4xx 错,那么重试或熔断是没有意义的,只有 5xx 才有意义)
    debuggerx
        63
    debuggerx  
       2021-12-26 12:31:37 +08:00 via Android
    抵制无脑 200 行为
    xuanbg
        64
    xuanbg  
       2021-12-26 17:29:18 +08:00
    @kevinlq 耗子别的观点我都赞同,就是这点不敢苟同。协议的归协议,业务的归业务不好吗,混起来真不好处理。至于监控和报警的问题,我认为还是要交给业务日志系统去处理,ELK 什么的又不是什么高深玩意。通常业务问题运维还真的处理不来,监控到了也是传话而已,不如直接研发上就完了。
    CEBBCAT
        65
    CEBBCAT  
       2021-12-26 17:49:08 +08:00
    @beginor #57 你认真的吗?
    bfdh
        66
    bfdh  
       2021-12-27 09:59:26 +08:00
    放 body ,原因无他,有些 APP 端 /前端菜鸟根本不懂 HTTP 状态码。别问我怎么知道的!!!
    yolee599
        67
    yolee599  
       2021-12-27 10:25:38 +08:00
    统一放 body ,因为可以用一套代码解析,假如一部分放 http code ,一部分放 body ,解析的时候要麻烦很多
    shequ2046
        68
    shequ2046  
       2021-12-28 15:12:27 +08:00   ❤️ 1
    国内主流的话程序员至少 9 成不知道啥是 HTTP ,同时也不存在高效的监控,运维也都是业余的,所以你也只能假装自己也啥都不懂,全放 body ,永远返回 200 。
    VeeSong
        69
    VeeSong  
       2022-01-15 17:06:31 +08:00
    http 基本的规范还是要遵守:
    4xx 是客户端错误,可能是用户访问了不存在的地址( 404 ),用户访问了不该访问的资源( 403 ),或者上面两者是因为前端 bug 导致,这种情况后端可以直接甩锅
    5xx 是服务端错误,后端接锅,具体什么错误可以在 body 里面说明

    上面有人说比较菜的前端不懂 http 就图省事,这种大是大非问题不应该迁就,不懂就让他们去学,学好来再来做。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5658 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 03:31 · PVG 11:31 · LAX 20:31 · JFK 23:31
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.