V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
azev
V2EX  ›  问与答

大家做后端开发时 会更改响应的 HTTP 状态码吗?

  •  
  •   azev · 2021-06-09 09:57:45 +08:00 · 5110 次点击
    这是一个创建于 1045 天前的主题,其中的信息可能已经有所发展或是发生改变。

    就是在后端代码把响应改成 403,500 什么的 然后返回自定义的 json 信息
    记得第一次见这个好些是看豆瓣的 api 接口
    对这个一直比较疑惑
    这样做会不会跟服务器某些情况下自己生成的 http 状态码混淆了?
    我个人倾向 不改这个响应 http 状态码 而是在 json 消息里再设置操作结果码

    不知道大家是怎么做?

    34 条回复    2021-06-10 10:01:40 +08:00
    fiypig
        1
    fiypig  
       2021-06-09 09:58:29 +08:00 via iPhone
    一般都自定义啊,code 自己设置
    manami
        2
    manami  
       2021-06-09 10:02:27 +08:00
    一般的 http 状态码不够用才自定义
    LeslieLeung
        3
    LeslieLeung  
       2021-06-09 10:02:55 +08:00 via iPhone   ❤️ 2
    跟你的做法一样 我觉得 http 状态码和 json 的状态码是要区分开的 json 的状态码设计可以参考阿里开发手册 可以很方便定位问题
    shenjinpeng
        4
    shenjinpeng  
       2021-06-09 10:10:42 +08:00   ❤️ 3
    以我接触过的大部分前端来看, 他们只认 200 ,其他一律服务器错误 ... 让他们根据 http code 做出相应的逻辑处理难比登天 .
    IvanLi127
        5
    IvanLi127  
       2021-06-09 10:15:00 +08:00
    2021 年了,我还是没找到为啥要在正常的响应中,额外在响应体里套一个 code 的合理性。。。 我自己的项目里都是直接用 http 状态码来做的,没遇到不够用的情况。具体错误信息响应体里带,也挺够用的。额外信息在请求头、响应头中带。平常看访问记录也很清晰
    guyeu
        6
    guyeu  
       2021-06-09 10:19:38 +08:00
    当年信了 V 站的邪,用 status_code 来定义业务异常,加了好多自定义的状态码,很蛋疼,想换回去。
    ChoateYao
        7
    ChoateYao  
       2021-06-09 10:26:42 +08:00
    实际上来说,http code 完成足够使用,但是额外在 json 中定义一个 code 主要是用于前端交互使用。

    比如注册接口,App 和 Web 以及大屏的交互逻辑个不一样,不同的错误需要 UI 做不同的交互操作。但是 http code 只有 403,额外定义一个 code 可以在不改后端的情况下,让前端自行处理。
    zpfhbyx
        8
    zpfhbyx  
       2021-06-09 10:40:02 +08:00   ❤️ 10
    我认为 http code 只是服务的状态 而不是业务的状态。。
    CEBBCAT
        9
    CEBBCAT  
       2021-06-09 10:47:04 +08:00
    楼主你这是转行过来的嘛…… 依据我有限的经验,服务器框架只会返回 200 和 500 给客户端,其他都是需要靠服务端代码指定的。

    按说学习 HTTP 的时候会顺便学习到 HTTP 状态码的。我的习惯优先用状态码表示,其次才是在 Response 中带上状态码
    passerbytiny
        10
    passerbytiny  
       2021-06-09 10:52:01 +08:00 via Android
    Spring Mvc 会自动给你加状态码,除非你好事的拦截全部异常然后强行返回 200 (和 response body 中的错误码)。

    Http 状态码跟业务错误码是分层共存而不是互斥的,你可以用 HTTP 状态吗返回通用错误信息,然后在 HTTP 500 的同时附加业务错误码来对 HTTP 500 Internal Server Error (内部错误异常)进行更为详细的说明。(事实上,原本应该用超过 500 的状态码,来当作 HTTP 500 的详情,但是这个不如上面的方式好用。)

    为了兼容性,往往会同时返回 HTTP 状态码和业务错误码。但如果只返回一个,那一定要是 HTTP 状态码,除非你的出发点就是“我 > 公共”。
    azev
        11
    azev  
    OP
       2021-06-09 11:00:11 +08:00
    @zpfhbyx 是的 就是这个意思 只要服务正常就应该返回 200 至于这个操作的响应 放在消息体里
    timethinker
        12
    timethinker  
       2021-06-09 11:03:46 +08:00   ❤️ 2
    2XX:请求成功
    4XX:客户端错误
    5XX:服务端错误

    如果只返回 200,不方便日志的收集和监控预警,因为把错误相关的信息都放到响应体内了,如果有日志相关的收集需求,那么就意味着要去解析响应体。

    见过很多前后端分离的项目,不管是成功还是失败,都一股脑返回一个包装体结构,里面大多有 3 个字段( code,message,data ),其实这三个字段不管在成功还是失败的情况下都存在冗余。

    比较推荐的做法是,HTTP 状态码仍然继续使用,该返回什么数据直接返回,也不需要一股脑全部加上一个包装体,还美其名曰为规范,在请求正常的情况下,code 和 message 是多余的字段,前端其实只需要里面的 data 。

    在错误的情况下( 4XX 和 5XX ),此时统一返回一种表达错误信息的格式才比较有意义,如果仍然返回之前的包装体,那么 data 字段也是冗余的。
    azev
        13
    azev  
    OP
       2021-06-09 11:10:59 +08:00
    @IvanLi127 @passerbytiny

    有些时候服务器返回的 500 并不是自己在代码里能控制的吧?
    而是服务器自己返回了 500 这个时候响应里是不是就没有业务错误信息了?
    处理起来会不会就比较困扰?
    lyusantu
        14
    lyusantu  
       2021-06-09 11:18:13 +08:00
    @azev 服务器返回 500,可以捕获异常呀,打印异常信息然后定位到具体业务错误的代码处
    shenjinpeng
        15
    shenjinpeng  
       2021-06-09 11:23:08 +08:00
    http code 本来就是可以自定义的, 就是个状态码 , 响应内容也是可以自定义的 .
    区别只是客户端是否按照协议来展示响应内容.
    未登录抛出 401, 前端拦截器直接跳到登录页面
    权限不够 403, 再附上一个 msg
    数据不存在返回 404
    前端传的数据有问题抛 400
    服务器异常抛 500
    等等...

    但是只用 http code 并不能描述所有内容, 也不能很好定位出问题的具体位置 . 所以大多数情况下还需加上具体的内容状态码 .
    heiheidewo
        16
    heiheidewo  
       2021-06-09 11:25:08 +08:00
    业务相关的错误码全部自定义。

    200 、404 、500 这些是通知浏览器或搜索引擎的
    WeKeey
        17
    WeKeey  
       2021-06-09 11:25:28 +08:00
    HTTP/1.1 200
    Content-Type: application/json

    {
    "ip": "1.1.1.1",
    "country": "澳大利亚",
    "province": "",
    "city": "",
    "isp": ""
    }


    HTTP/1.1 400
    Content-Type: application/json

    {
    "code": 101001,
    "message": "ip 地址错误"
    }
    icyalala
        18
    icyalala  
       2021-06-09 11:31:33 +08:00   ❤️ 3
    如果用 http code 来定义业务错误,以后业务复杂了会很麻烦的,
    比如楼上按未登录 401,权限不够 403,以后又出现什么非 VIP 会员、非黄金会员、未预约之类的各种奇葩需求,
    扩展起来就麻烦得很了。

    如果 http code 和 JSON 里面使用两套 code,那开发和调试就变得麻烦。
    不如统一用 JSON 来自定义错误信息,除此以外都是网络或者服务器问题。
    liuidetmks
        19
    liuidetmks  
       2021-06-09 12:25:45 +08:00
    额外搞一套 httpcode,我感觉是给自己埋坑,把服务器状态和业务搅和在一起。
    hehezhang
        20
    hehezhang  
       2021-06-09 12:29:35 +08:00 via Android
    服务状态码和业务码不应该分开吗,
    mingmeng
        21
    mingmeng  
       2021-06-09 13:10:28 +08:00 via Android
    http 给接入层用,就是给接入 ng 用。一般逻辑层故障或者接入层负载均衡有问题才会有 http code error,这时候请求压根没打到逻辑层。

    body 里的错误码用来标记业务错误,因为上游要根据不同的业务错误来做逻辑判断和区分显示。如果拿到了 body 的错误码那么 http 一定是 200,意味着接入网关没问题,逻辑层处理可能有问题
    BeautifulSoap
        22
    BeautifulSoap  
       2021-06-09 13:21:35 +08:00   ❤️ 1
    上面说用 StatusCode 定义错误就够了的,是真没处理过一些复杂业务?
    比如光是一个登陆错误,就有密码错误、账号错误、验证码错误、账号被封禁、账号被移除、账号频繁登陆被限制、账号被风控、账号登陆 ip 有问题,服务器内部错误等等一堆业务逻辑。这还只是账号登陆这一个业务接口。当然这些异常并不一定是每个都要细分,但是当有需要进行错误细分并进行不同业务处理的时候,你觉得 4xx,5xxx 这些够吗。当然你 status code 要从 001 用到 999 也不是不可以,但你确定真要这么干吗?
    snoopyhai
        23
    snoopyhai  
       2021-06-09 13:32:10 +08:00
    建议 http 状态码不要去碰. 留给第三方监控. 毕竟是服务器 or 服务状态.
    业务状态都在 200 下的 json 里定义
    clf
        24
    clf  
       2021-06-09 13:34:06 +08:00   ❤️ 1
    我开发时 json 里返回的 code 并不是 http 状态码。code 是业务执行是否成功的判断。

    而 http 状态码则是用通用的标准,两个区分开。

    请求成功就是 200 的 http code,但返回 json 的 code 可能是 0 成功 >0 业务逻辑控制的 Code 。

    请求错误(非业务错误)返回 500 的 http code,返回的 json 里的 code 是小于 0 的一个异常追踪 ID 。就是雪花算法生成的一个随机 ID 的负数,在日志系统里抛出异常的时候也会记录一样的 ID 。

    角色权限相关返回 40X 的 http code,返回的 json 里的 code 是小于 0 大于-1000 内的特定 code 。

    具体的返回结构:code 是业务 code,msg 是前端提示信息,data 是数据,trace 是请求的追踪 ID,version 是接口版本

    {
    code:xxx,
    msg:xxx,
    data:xxx,
    trace:xxx,
    version:xxx
    }
    SjwNo1
        25
    SjwNo1  
       2021-06-09 14:00:49 +08:00
    我发现有些人总是把状态码和业务 code 混为一谈
    IvanLi127
        26
    IvanLi127  
       2021-06-09 15:29:18 +08:00
    @azev #13

    如果是你开发的服务,HTTP 状态码都是可控的,一般的框架都有全局拦截器之类的东西,可以统一处理响应,尤其是异常的响应。
    服务器自己返回 500 只是默认表现,你可以覆盖你自己需要的状态码。
    处理起来如果困扰的话,一定是框架问题。正常的框架都能支持这个操作的。
    PerFectTime
        27
    PerFectTime  
       2021-06-09 16:29:59 +08:00
    分开的好,揉在一起搞的想死。。
    bsg1992
        28
    bsg1992  
       2021-06-09 17:57:33 +08:00
    说直接用 http code 代替应用返回的状态 肯定又是一堆被 restful 洗脑的教徒
    lqs
        29
    lqs  
       2021-06-09 19:11:21 +08:00   ❤️ 1
    icylogic
        30
    icylogic  
       2021-06-09 20:00:12 +08:00 via iPhone
    ttk, yzmttk
    karloku
        31
    karloku  
       2021-06-09 20:44:23 +08:00
    至少 2xx 和 4xx 要区分开. 5xx 是服务器出错, 一个业务应用不应该自己使用这个码, 让框架来生成.

    业务状态码是业务状态码, HTTP 状态码是 HTTP 状态码. 不能混为一谈. 两者不冲突.

    HTTP 状态码是用来方便你的网络中间件, 运维工具, 以及客户端的网络请求模块进行统计和分类处理.
    业务状态码是提供给客户端应用进行业务逻辑处理.
    fff333
        32
    fff333  
       2021-06-09 20:46:13 +08:00 via Android
    @LeslieLeung 阿里的手册有链接么?谢谢
    uselessVisitor
        33
    uselessVisitor  
       2021-06-09 21:08:48 +08:00
    如果使用 ResponseEntity 的话,还是 HttpStatus 比较常用吧。。
    janxin
        34
    janxin  
       2021-06-10 10:01:40 +08:00
    当然不会产生混淆。关于定义,可以参考其他厂商的做法,比如 Paypal:

    https://github.com/paypal/api-standards/blob/master/api-style-guide.md#http-status-codes
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3909 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 05:08 · PVG 13:08 · LAX 22:08 · JFK 01:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.