首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Livid
V2EX  ›  API

关于在设计 API 时的一个考虑

  •  
  •   Livid · 2012-04-16 22:57:00 +08:00 · 9774 次点击
    这是一个创建于 2843 天前的主题,其中的信息可能已经有所发展或是发生改变。
    如果用户请求的时候提交了错误的参数,这个时候服务器端无法满足用户的需求,需要返回一个错误页面。

    假设 API 是 JSON 格式的,那么大家做为开发者,会希望服务器端如何通知这个错误呢?

    目前考虑的几种做法:

    1. 返回 HTTP 400 Bad Request 状态。

    2. 在所有的 JSON 反馈中都加入这样的设定:

    {
    "status" : "error"
    }



    {
    "status" : "ok"
    }

    期待大家对这个问题的建议。
    59 回复  |  直到 2016-08-10 11:20:19 +08:00
    adow
        1
    adow   2012-04-16 22:59:12 +08:00
    我倾向400 Bad Request
    avatasia
        2
    avatasia   2012-04-16 23:00:37 +08:00
    不符合规则的参数一律 404
    status error 或者 1 表示系统错误
    status 0 或者 没有 OK
    cjou
        3
    cjou   2012-04-16 23:02:35 +08:00
    我习惯用 responseCode + msg 的方式,显示错误信息对调试或捕捉日志会更直接。
    {
    "status" : "200"
    "msg" : "sth error"
    }
    lychee
        4
    lychee   2012-04-16 23:02:40 +08:00
    1和2可以同时使用

    我觉得可以加个/path/to/api?show_messages=1 来决定是否返回错误信息 可以稍稍省点流量
    iandyh
        5
    iandyh   2012-04-16 23:02:44 +08:00
    2

    这样应用处理异常起来也更方便,每次调 API 后判断一次 status 是否 ok 就可以进行下去。
    whtsky
        6
    whtsky   2012-04-16 23:03:27 +08:00 via Android
    400
    Los
        7
    Los   2012-04-16 23:09:29 +08:00
    返回 HTTP status code,并在有错误出现时返回数据格式中加入 errors
    如用户登录出错返回 HTTP status code 为 401 Unauthorized,数据格式为以下

    {
    "errors":
    {"type":"unauthorized","msg":"Login failed. Email or password are incorrect."}
    }
    whtsky
        8
    whtsky   2012-04-16 23:11:23 +08:00 via Android
    ls+1.
    既然已经有status code了,就没必要再从数据中表示一遍.
    zhendi
        9
    zhendi   2012-04-16 23:13:29 +08:00
    同3楼, 习惯返回 {"status": "error", "message": "error msg"}
    Los
        10
    Los   2012-04-16 23:13:49 +08:00
    @whtsky 有时候 HTTP status codes 并不能完全的表述出错的类型
    fanzeyi
        11
    fanzeyi   2012-04-16 23:16:05 +08:00
    400 + {"status": "error", "message": "error msg"}

    如果是 200 就不用再有 status 和 message 了
    bjshdq
        12
    bjshdq   2012-04-16 23:24:25 +08:00 via iPod
    2
    这样更清晰。
    clowwindy
        13
    clowwindy   2012-04-16 23:25:20 +08:00
    用 status code 区分成功和失败,成功和失败返回不同的数据,由不同的 callback 处理。所以成功不需要返回错误信息,出错才需要。
    icyflash
        14
    icyflash   2012-04-16 23:26:18 +08:00
    客户端通过http status code来判断请求是否成功。

    非200的返回error message

    可以参考下twitter的嘛,

    https://dev.twitter.com/docs/error-codes-responses
    DeeCheung
        15
    DeeCheung   2012-04-16 23:34:50 +08:00
    python 的理念 None
    darasion
        16
    darasion   2012-04-16 23:37:26 +08:00
    我也挺纠结这个问题的,收藏,看大家有啥高见。
    xiaojay
        17
    xiaojay   2012-04-16 23:43:13 +08:00
    http://wiki.open.t.qq.com/index.php/错误码说明

    我觉得 tqq 的api 返回代码,不错
    chuck911
        18
    chuck911   2012-04-16 23:50:32 +08:00
    只用400太笼统了
    401、403、201、404 都很常用
    http code和json内容不冲突,
    方法2可以与http code同时使用
    darcy
        19
    darcy   2012-04-16 23:53:54 +08:00
    @Los +1
    HTTP的状态码实在有限,某些情况下需要自定义的字段才能表示一些复杂的异常情况。
    cashplk
        20
    cashplk   2012-04-17 00:00:09 +08:00
    400比较清晰
    adow
        21
    adow   2012-04-17 00:10:31 +08:00
    我现在的做法是使用status code, 甚至在post/put操作成功时也使用 200/201/202,而正文中只输出正确操作数据的json格式

    比如$.ajax在出错时直接在error:function(xhr)中进行处理,而不用每次在返回中判断是否正确的状态了。

    类似 http://www.douban.com/service/apidoc/reference/common#返回状态说明
    leiz
        22
    leiz   2012-04-17 00:16:00 +08:00
    返回http status code + 自定义error code, 不需要返回错误信息,提前定义好error code对应的错误信息就行。把自定义的错误信息添加到返回里不太合适。
    freefcw
        23
    freefcw   2012-04-17 00:28:41 +08:00
    还是带上error code比较好吧,msg这个东西有总比没有好
    guoquan
        24
    guoquan   2012-04-17 01:52:29 +08:00
    400+错误信息
    Semon
        25
    Semon   2012-04-17 02:17:48 +08:00
    errorCode + errorMessage
    ultragtx
        26
    ultragtx   2012-04-17 02:23:05 +08:00
    1+2吧
    ratazzi
        27
    ratazzi   2012-04-17 07:32:18 +08:00 via Android
    我比较倾向于后者,可以参考 jsonrpc2 的方式
    iwege
        28
    iwege   2012-04-17 08:22:17 +08:00
    最好是以共用的形式来做,两者并不冲突。
    runsheng2005
        29
    runsheng2005   2012-04-17 08:36:13 +08:00
    通常采用 status 标示状态,再外加一个 errinfo 来标示错误信息!
    tox
        30
    tox   2012-04-17 08:49:55 +08:00
    两种同时使用
    1,http协议异常,或请求参数不符合,在http响应头加入错误码
    2,JSON中得"status" : "error" 代表业务错误,如注册得时候用户名重复等类似这样得异常
    lqs
        31
    lqs   2012-04-17 08:53:51 +08:00
    注意,有些ISP会把非2xx的http response劫持成自己的广告页面。
    virushuo
        32
    virushuo   2012-04-17 16:09:15 +08:00
    我比较喜欢foursquare的模式。

    参考: https://developer.foursquare.com/overview/
    reorx
        33
    reorx   2012-04-17 16:51:22 +08:00
    http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
    "The request could not be understood by the server due to malformed syntax"

    http://www.checkupdown.com/status/E400.html
    "The Web server (running the Web site) thinks that the data stream sent by the client (e.g. your Web browser or our CheckUpDown robot) was 'malformed' i.e. did not respect the HTTP protocol completely. So the Web server was unable to understand the request and process it. "

    虽然我自己也是用400,不过我一直对自己对400的理解有疑问。根据以上的描述,似乎400专指协议上有问题,即HTTP请求本身不能被server理解,而非HTTP请求被解析,但逻辑上的参数不正确的情况。

    也许只是钻牛角尖吧,大家不用在意,毕竟各大网站使用多年了。

    实际项目中和@cjou 用的是同样的方式。
    leben
        34
    leben   2012-04-17 17:35:03 +08:00
    倾向于只要不是404错误,全部返回有意义的状态和信息。
    如果status是error,最好有完整的错误信息。
    这样不需要很完善的api使用文档,就可以比较顺利的使用api。
    levey
        35
    levey   2012-04-17 17:55:23 +08:00
    一般是error code。。。
    ElmerZhang
        36
    ElmerZhang   2012-04-17 18:06:02 +08:00
    详细错误原因肯定要在body中写明的,格式可以是这样
    {errno:xx, error:'', data:''}
    errno为0时为成功,其他是失败。
    也可以结合http状态码来做,但是不能错误全404,状态码一定要和错误的含义对的上,例如找不到对象是404,授权失败是401之类,写成功读成功用200,删除成功用204等等
    acen
        37
    acen   2012-04-17 18:12:39 +08:00
    我统一返回200, json格式{success:true/false, data:xxx, msg:xxx}
    sobigfish
        38
    sobigfish   2012-04-17 19:30:39 +08:00
    api不是面向最终用户的 其实http状态码意义不大,而且js lib之类也不能很好的支持,所以还是json格式的错误代码比较有用。
    flowercold
        39
    flowercold   2012-04-17 19:47:46 +08:00
    做过的一个快递查询类的api,对于此类情况,使用的是第2种办法

    {"message":"EMS快递单号是由E开头的字母,CS/CN结尾的字母加上中间9位的数字组成的,请检查相关单号。","status":"0"}


    "status"分几类情况,单号查询的数据源正常,单号查询的数据源异常,单号异常,单号正常暂无记录等等;
    bhuztez
        40
    bhuztez   2012-04-17 19:56:52 +08:00
    @sobigfish SOAP就是这么想的
    Johnny
        41
    Johnny   2012-04-17 20:00:07 +08:00
    参数错误应该是服务要处理的一部分,正确的应该是服务成功,返回200 但是处理结果是返回状态Error,400应该是本身服务出现问题而出现的。
    zythum
        42
    zythum   2012-04-17 23:22:11 +08:00
    还是统一返回200. 然后传状态码的方式
    leeiio
        43
    leeiio   2012-04-17 23:30:11 +08:00
    基本形态,如需要返回别的就在这个基础上叠加字段
    {
    "code":"xxxxx",
    "message":"xxxxxxx"
    }
    code是自己定义的错误编号代码例如E001之类的,message是方便查看输出的错误

    参数错误用400状态码,比较疑惑你的status还区分ok和error的做法
    egen
        44
    egen   2012-04-17 23:57:54 +08:00
    取决于是不是想做成RESTful的,如果RESTful就400
    否则就200+状态码,另外很多时候RESTful在业务逻辑方面的问题的时候还是需要额外的状态码的
    vagase
        45
    vagase   2012-04-17 23:59:22 +08:00
    同意7楼,充分利用Http Error Code,这样也可以简化客户端的处理。可以很好的兼容第三方库,比如像iOS RestKit,针对返回不是200的统一error处理,只要返回200就表明数据正常,直接处理正常情况了。
    88250
        46
    88250   2012-04-18 00:34:02 +08:00
    还是 1 + 2 比较好:

    1. 对不是充分了解 response 格式约定的客户端来说也能通过 sc 大致读懂 response 意义
    2. { "status": xxx } 这里最好还是使用 HTTP status codes,虽然有点重复,但能保证和 response 一致,简单。自定义状态码会显得太累赘,这只是个约定问题。

    综上,示例:

    {
    "sc": 400,
    "msg": "Required [xxx] parameter"
    }

    {
    "sc": 200,
    "msg": "Processes Successfully"
    }

    P.S. "msg" 在服务器处理 i18n。
    wxianfeng
        47
    wxianfeng   2012-04-18 10:16:39 +08:00
    我们的

    { status: 1 }

    { status: 0, error: "xxx" }
    jackyz
        48
    jackyz   2012-04-18 12:49:10 +08:00
    success :[0, result]
    error :[1, error]
    result 和 error 都是 json 。

    为毛呢?

    0, 符合直觉。0 = ok, 1 = err 符合“直觉”。

    1, 易于解析。此形式大概也是 success 和 error 语义的“最小包装”了。在服务端,可以统一写一个 errror handler 。在客户端,可以统一 override jquery 写一个简单的解析就 ok 了。

    3, 支持 jsonp 调用。
    jackyz
        49
    jackyz   2012-04-18 12:52:52 +08:00
    example:

    比如,注册:

    > POST /register {name:"", pass:"123"}
    < [1, {name: "is_null", pass: "too_short"}]

    or

    > GET /register "name=&pass=123&_method=post&callback=jsonp"
    < jsonp([1, {name: "is_null", pass: "too_short"}]);
    freewizard
        50
    freewizard   2012-04-18 13:26:55 +08:00
    @livid 两者都需要
    HTTP body必须保持一个合法JSON格式,避免客户端因为异常处理不完善而出错。错误代码和信息最好也在JSON内,这样客户端内部保存和传递数据时就不需要额外的将HTTP头和JSON合并了。
    HTTP status code必须为非2xx,这样对调试和运维很方便,并且避免HTTP 200误导代理或缓存服务器。
    sdpfoue
        51
    sdpfoue   2012-05-19 20:20:29 +08:00
    {errno:0/1/2,errmsn:''/'some message'}
    sd4399340
        52
    sd4399340   2012-05-19 23:08:25 +08:00
    选择2
    MayLava
        53
    MayLava   2012-05-19 23:11:10 +08:00
    觉得HTTP状态还是必要的。
    至于html正文的话倒是无所谓,看需求吧。
    ljbha007
        54
    ljbha007   2012-05-19 23:59:42 +08:00
    两个一起用
    这样客户端通过HTTP status code得知有错误 通过JSON得知错误类型及文字描述
    arthur369
        55
    arthur369   2012-05-20 08:45:58 +08:00
    咦。这里好多程序员
    iceseaboy
        56
    iceseaboy   2014-05-08 12:46:06 +08:00
    就想知道 为什么要把 业务逻辑 和 HTTP状态 混在一起。。。
    kslr
        57
    kslr   2014-11-19 10:27:05 +08:00
    一直是返回400状态 ,然后显示错误{错误码,错误信息,错误详解,比如文档连接}
    system
        58
    system   2016-08-10 11:20:11 +08:00
    @clowwindy 如果业务不同的错误类型,比如我要提现操作,可能会出现银行卡未绑定、没有上传户口本,没有上传身份证,没有绑定手机号码,没有填写住址等错误,没有余额等等。 http status 的错误码是多少 看了文档没有找到意思一样的、
    system
        59
    system   2016-08-10 11:20:19 +08:00
    @kslr 如果业务不同的错误类型,比如我要提现操作,可能会出现银行卡未绑定、没有上传户口本,没有上传身份证,没有绑定手机号码,没有填写住址等错误,没有余额等等。 http status 的错误码是多少 看了文档没有找到意思一样的、
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2410 人在线   最高记录 5168   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 35ms · UTC 14:36 · PVG 22:36 · LAX 06:36 · JFK 09:36
    ♥ Do have faith in what you're doing.