RESTful Status in Deep

在 RESTful 中,Status Code 是 Sever 和 Client 通讯中第一个用到的标准。业界有一些很好的总结,这里记下自己的实践。

0x01: 成功类:

成功类的请求就相对简单了,直接返回对象就可以了(Modern Web App 中其实是不需要外面包一层 Envelope)。

200 Success GET, PATCH 表示返回正常 返回对象 { ...}
201 Created POST 表创建成功 会返回创建对象 { ... }
204 No Content DELETE 表删除成功,且不返回数据

POST, PUT, PATCH 都会返回该操作对象,只是 POST 有特殊 Code 201,其它都用 200


1x10: 失败类:

4XX Client Error:

400 Bad Request The request is malformed, such as if the body does not parse。 无效的请求,语义有误,当前请求无法被服务器理解
401 Unauthorized Bad credentials 未验证
403 Forbidden 未授权
404 Not Found 内容不存在,无论请求一个错误的地址,还是指定 id 不存在
409 Conflict 由于和被请求的资源的当前状态之间存在冲突,请求无法完成。这个代码只允许用在这样的情况下才能被使用:用户被认为能够解决冲突,并且会重新提交新的请求。该响应应当包含足够的信息以便用户发现冲突的源头。
410 Gone Indicates that the resource at this end point is no longer available. Useful as a blanket response for old API versions
422 Unprocessable Entity Used for validation errors
423 Locked 当前资源被锁定。
429 Too many request Rate limit exceeded, throttling
451 Unavailable For Legal Reasons (由IETF在2015核准后新增加)该访问因法律的要求而被拒绝

具象化的使用 Status code:

  • The request could not be understood by the server due to malformed syntax
  • 409

5XX Server Error:

500 Internal Server Error 服务器内部错误,不受程序管理
501 Not Implemented 该接口未实现


1x20: 错误的格式 (Error Object)

业界一般的做法是返回 code 和 message 这两个字段

  • code 用于显示出错信息,客户端可定义。
  • message 一般是给 API 调用者看的,对开发友好。

有些需求是会返回一个 Error 数组,好处是,如果 API Body 中有多个值,可以分别校验,返回具体每一个值的出错信息,更友好。

1
2
3
4
5
6
7
8
9
10
11
12
13
# Github
{
"message": "Problems parsing JSON",
"documentation_url": "https://developer.github.com/v3"
}
# Twitter
{
"errors": [{
"code": 135,
"message": "Timestamp out of bounds."
}]
}


1x30: 案例分析

1x31: Client Data Error

服务器无法理解这个请求。如果 request 包括无法解析的数据,应该返回一个 HTTP 400:

  • request 中包含的是一个无效的 JSON
  • request 缺少有效的 Query Parameters
1
2
3
4
5
6
7
8
# Status: 400 Bad Request
{
"errors": [{
"code": 4003,
"message": "Problems parsing JSON"
}]
}

1x32: 无法通过验证

之前通常会用 HTTP 400 错误码来标识用户提交的错误信息,但这个码太通用了,有时无法更具象表述出错信息。

Validation Errors 通过 HTTP 422 (Unprocessable Entity) 会比 HTTP 400 更具象,更合理。

Request matched and met syntactic contract but validation failed

1
2
3
4
5
6
7
8
# Github
# Status: 404 Unprocessable Entity
{
"message": "Problems parsing JSON",
"documentation_url": "https://developer.github.com/v3"
}

1x33: 用户相关的几个实例:

  • 密码错误: 这也是用户上传的数据也合格,但不能够通过 validation ,属于 HTTP 422 的范畴。
  • 但如果去访问一个资源,该资源需要 token,这时就是 HTTP 401。
  • 还有,如果有了 token ,但该资源需要特定的权限,这就是 HTTP 403。

1x34: 案例分析1:优惠券次数

举例:抢优惠券的业务,每个人有 3 次机会,如果用户前 3 次内点,和第 4 次请求,应如何处理。

但在这件事的最后定论是:这是一个业务问题,不应该在 HTTP 协议中来体现,所以最终请求会是这样:

1
2
3
4
5
6
{
"data": {
"success": true,
"prize": 1
}
}

事过情迁,我再去写 RESTful 时,发现这样并不好。首先先谈下好的方案:

Rate Limit Solution

HTTP 是有这种情况的方案的,Rate Limit,在 Header 中显示该接口的可调用情况:

X-RateLimit-Limit -
X-RateLimit-Remaining -
X-RateLimit-Reset -

超过三次后的请求

返回 403 Forbidden

1
2
3
4
5
6
7
8
9
10
11
HTTP/1.1 403 Forbidden
Date: Tue, 20 Aug 2013 14:50:41 GMT
Status: 403 Forbidden
X-RateLimit-Limit: 3
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1377013266
{
"code": 88,
"message": "API rate limit exceeded for xxx.xxx.xxx.xxx or username."
}

1x35: 案例分析1:兑奖

兑奖码无效

HTTP 404

未中奖

理论上未中奖是不能进入的,前端会限制的,但如果被绕开了,还是会有请求到达。

  • HTTP 400 Bad Request
  • HTTP 422 Unprocessable Entity

该码已兑换过

跟上一个一样

  • HTTP 409 Gone 忆兑换过,所以是用过了,Gone
  • HTTP 400 Bad Request 客户端为什么还要发这样的请求?所以是 Bad request
  • HTTP 422 Unprocessable Entity 因为后端验证出了问题。
  • HTTP 423 Locked 因为兑换过就被锁定了。

用户输入兑奖信息不完整 (unpassed validation) ( HTTP 409)

更多 Rate Limit 参见:


REF::