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

想给所有的业务异常一个统一固定的 HTTP 状态码,用什么合适? 403? 409? 422?

  •  1
     
  •   param · 239 天前 · 2523 次点击
    这是一个创建于 239 天前的主题,其中的信息可能已经有所发展或是发生改变。

    http 状态码能不能用-1 的。

    不要 200 ,那样我就要在 response 再包一层。 我想给业务异常统一固定的 HTTP 状态码,例如 403 ,那么我遇到 403 才会拆开看里面的业务异常,在 403 的 response 里返回大写字母格式的错误码以及 err msg 。如果遇到 200 ,就默认没有异常,不需要拆开了。

    业务异常指的是,诸如「未完成的订单不允许评论」之类的

    403 经常被认为是「权限不够,换个身份操作就可以成功」的意思,但它其实应该是「 forbidden 」,没有说明是权限不够而 forbidden ,或者其他原因的 forbidden 。具体原因还是可以在 body 里看。

    这个问题在这里好像吵得很厉害,我不想对 200 再封一层,同时也需要自定义的状态码,这完全不矛盾呀。

    32 条回复    2023-09-07 23:25:49 +08:00
    dzdh
        1
    dzdh  
       239 天前
    非要定一个比较合理的规范的话。可以考虑 guzzle 的封装

    由于提交的参数有问题的 4xx

    - 资源不存在( id?=x ) 404
    - 缺少参数,参数不合法 400
    - 不能操作这个资源 (?id=xx ) 403

    class X extends Exception {}

    class X404 extends X{}

    class X400 extends X{}

    class ResourceNotFound extends X404 {}
    param
        2
    param  
    OP
       239 天前
    @dzdh 如果要细分的话,很容易选择困难。。所以业务层的异常还是统一同一个码就好了。
    otakustay
        3
    otakustay  
       239 天前
    毫无疑问的 400 吧
    dzdh
        4
    dzdh  
       239 天前
    @param

    我是统一 200 code, result, mark, data :doge:
    xfn
        5
    xfn  
       239 天前
    我的理解是如果是调用方的问题返回 4xx ;服务提供方的问题返回 5xx ;你这种情况应该是调用方没有满足业务期望的条件,个人认为 400 比较合适
    mritd
        6
    mritd  
       239 天前
    感觉应该 400 好点吧, 不过确实很多业务系统喜欢 200 all in... 他们却是也有一些理由, 就是某些 http 库非 200 可能抛 异常啥的; 不过我没写过客户端还是不太了解, 我个人理解 HTTP CODE 应该是更高层次的、笼统一点的错误提示, 而内部 body 可以附加业务层次的特定错误描述.
    param
        7
    param  
    OP
       239 天前
    @otakustay 请求格式错误才是 400 吧,例如本该用 application/json 的却用了 multipart/form-data
    otakustay
        8
    otakustay  
       239 天前
    @param #7 所有客户端的错误都是 400 ,请求格式错误 415
    fredweili
        9
    fredweili  
       239 天前
    除了 code ,还能再传一个 header
    param
        10
    param  
    OP
       239 天前
    @fredweili 咦,这么说,错误码直接放 header 就可以
    param
        11
    param  
    OP
       239 天前
    @fredweili 那问题来了,header 用什么名好呢。
    grissom
        12
    grissom  
       239 天前
    那明显是 http 定义的以外的任意 code 了
    Morii
        13
    Morii  
       239 天前
    CodeCodeStudy
        14
    CodeCodeStudy  
       239 天前   ❤️ 2
    不要修改 HTTP 状态码,HTTP 状态码应该是由 Nginx 之类的 web 服务器来掌控,业务上的状态应该自己搞一套状态码来表示。
    如果是 401 的话,比如 Nginx 设置了 auth_basic ,需要输入用户名和密码,用户名和密码不对的话就是 401 。
    如果是 403 ,那就是不给看就不给看。
    个人建议使用自定义的业务的状态,用大于 1000 的数字来表示。
    zjw7sky
        15
    zjw7sky  
       239 天前
    这样是不是不利于拓展
    iOCZ
        16
    iOCZ  
       239 天前   ❤️ 4
    建议区分 http status code 和 business status code
    loading
        17
    loading  
       239 天前
    我觉得合理的方法是:
    api 正确响应了就返回 200 ,把 http 状态码留给网络问题。

    api 的错误,例如找不到货物(不是 url 找不到的 404 ),就 HTTP 200 ,然后返回的数据一般是这样:

    {
    code:404,
    msg:'找不到货物',
    data:[]
    }

    其中 code 部分参考 http 的码来做,msg 是给人看的信息,或者作为提示信息。

    我非常喜欢这种方式,希望能帮到你。
    dallaslu
        18
    dallaslu  
       239 天前
    按规范来吧,只用标准的 http 状态码,其他业务上的错误码请在 body 里自行定义
    QlanQ
        19
    QlanQ  
       239 天前   ❤️ 2
    名字就叫 http 状态码,为什么要和业务相关?
    如果你用户名密码错误,这是 业务上的错误,http 的请求是成功的

    从后续处理上来讲,前端在遇到不是 200 的情况的下,都是不解析具体 响应的,不是 200 就被认为是 请求有问题,
    和断网类似
    zerduo
        20
    zerduo  
       239 天前
    那你不随便嘛,只要是 http 状态码,统一就行,跟前端定好了无所谓,一个数字而已
    yolee599
        21
    yolee599  
       239 天前 via Android
    http 请求到达了你业务程序,你就应该返回 200 ,业务代码再在 body 中单独定义
    sujin190
        22
    sujin190  
       239 天前 via Android
    body 结构不一致才是真的坑死人,每次遇到这种都觉得这么干的人真是脑子进水了
    Masoud2023
        23
    Masoud2023  
       239 天前
    非要用 http 状态码就老老实实 RFC

    不要自己造状态码,body 里 errorCode 不磕碜,自己乱造小心到时候各种中间件找你麻烦
    clf
        24
    clf  
       239 天前
    只用标准的 http 状态码,业务异常则是 Http 200 ,但 body 的 code 返回其他的。
    fivesmallq
        25
    fivesmallq  
       239 天前
    参考 stripe 设计 https://stripe.com/docs/api/errors?lang=curl

    ```sh
    curl https://api.stripe.com/v1/payouts \
    -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
    -d amount=11a00 \
    -d currency=usd
    {
    "error": {
    "code": "parameter_invalid_integer",
    "doc_url": "https://stripe.com/docs/error-codes/parameter-invalid-integer",
    "message": "Invalid integer: 11a00",
    "param": "amount",
    "request_log_url": "https://dashboard.stripe.com/test/logs/req_H7WCCMvEpRyv9s?t=1693547819",
    "type": "invalid_request_error"
    }
    }

    ```

    也可以不加 error 那一层,直接返回里面的内容。
    scung
        26
    scung  
       239 天前
    用 HTTP 418 状态码😊
    TPOB
        27
    TPOB  
       239 天前
    现在大家的用法其实是把 http 当传输层协议在用,那 http 的状态码就应该统一是 200 (传输没有异常)。业务的异常就放在 body 里面才对
    cylx3124
        28
    cylx3124  
       239 天前   ❤️ 1
    https://github.com/spring-projects/spring-framework/blob/main/spring-web/src/main/java/org/springframework/http/HttpStatusCode.java#L39C2-L77C20

    https://github.com/spring-projects/spring-framework/blob/main/spring-web/src/main/java/org/springframework/http/HttpStatus.java#L36C1-L424C95

    Spring 文档给出了对的 http code 详细解释,建议先看一下 Spring 对 http status 的定义,然后思考下 4xx 客户端异常、5xx 服务端异常和业务异常的区别,想明白以后你的问题自己心里应该就会有答案。
    zhzy0077
        29
    zhzy0077  
       239 天前
    要么你就正经按照错误类型去找最合适的 http code ,虽然对于绝大多数业务 4xx 和 5xx 是绝对不够用的。
    要么你就干脆一律 200 ,然后用 flag 去标有没有成功。
    一半一半的容易把自己和同事绕进去
    wu00
        30
    wu00  
       239 天前
    符合规范的只用了这几个,基本上是网关层/代码底层控制的
    401 ,403 ,404 ,415 ,502 ,500

    开发中约定俗成的由开发人员控制的就两个
    200 ,成功一律 200 ,不区分 201 、204 等等
    400 ,业务异常一律 400 ,包一个对象定义异常类型{errorCode, errorData, errorMessage}

    真要按照标准规范无疑是找罪受...
    agagega
        31
    agagega  
       239 天前 via iPhone
    以前接手过一个 php 项目,错误统一 404…
    param
        32
    param  
    OP
       233 天前
    @CodeCodeStudy 没错啊,我不是说了用自定义的业务状态码吗。只是客户端要在遇到业务异常时才需要去看业务状态码,所以需要一个 http 状态码来表示出现了业务异常。

    @iOCZ 我不是已经区分了吗。我 http 状态码只是用来标记有没有出现业务异常,而具体的业务异常肯定是用业务状态码表示啊。

    @dallaslu 我不是说了把业务异常放在 body 里定义了吗。只是我需要先判断是否成功,再决定要不要拆开 body 看业务异常。如果是 200 我就不用拆开看 body 里的东西了。

    @TPOB 对啊,业务异常放在 body 啊。现在要用一个 http 状态码表示业务是否成功,不成功的话就看 body 里给了什么业务异常。

    楼上已经说了,用 400 了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1472 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 17:00 · PVG 01:00 · LAX 10:00 · JFK 13:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.