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

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

  •  1
     
  •   param · 2023-09-01 10:08:49 +08:00 · 2832 次点击
    这是一个创建于 442 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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  
       2023-09-01 10:12:51 +08:00
    非要定一个比较合理的规范的话。可以考虑 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
       2023-09-01 10:14:53 +08:00
    @dzdh 如果要细分的话,很容易选择困难。。所以业务层的异常还是统一同一个码就好了。
    otakustay
        3
    otakustay  
       2023-09-01 10:17:24 +08:00
    毫无疑问的 400 吧
    dzdh
        4
    dzdh  
       2023-09-01 10:17:35 +08:00
    @param

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

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

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

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

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

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

    不要自己造状态码,body 里 errorCode 不磕碜,自己乱造小心到时候各种中间件找你麻烦
    clf
        24
    clf  
       2023-09-01 13:41:16 +08:00
    只用标准的 http 状态码,业务异常则是 Http 200 ,但 body 的 code 返回其他的。
    fivesmallq
        25
    fivesmallq  
       2023-09-01 13:59:02 +08:00
    参考 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  
       2023-09-01 14:28:54 +08:00
    用 HTTP 418 状态码😊
    TPOB
        27
    TPOB  
       2023-09-01 15:47:04 +08:00
    现在大家的用法其实是把 http 当传输层协议在用,那 http 的状态码就应该统一是 200 (传输没有异常)。业务的异常就放在 body 里面才对
    cylx3124
        28
    cylx3124  
       2023-09-01 17:32:10 +08:00   ❤️ 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  
       2023-09-01 18:22:27 +08:00
    要么你就正经按照错误类型去找最合适的 http code ,虽然对于绝大多数业务 4xx 和 5xx 是绝对不够用的。
    要么你就干脆一律 200 ,然后用 flag 去标有没有成功。
    一半一半的容易把自己和同事绕进去
    wu00
        30
    wu00  
       2023-09-01 18:51:03 +08:00
    符合规范的只用了这几个,基本上是网关层/代码底层控制的
    401 ,403 ,404 ,415 ,502 ,500

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

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

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

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

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

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