在最近的项目中,我发现不少人在设计 REST API 的时候,往往仅仅通过应用层的协议来返回调用的状态,而忽略了 HTTP 状态码本身的含义。
本文参考 https://restfulapi.net/http-status-codes,我在这里做一个简化版本,列出常见、但是往往会忽略使用的错误码。
分类
分类 | 描述 |
---|---|
1xx: Informational | 用于协议握手阶段的临时应答 |
2xx: Success | 客户端的请求被成功地接收 |
3xx: Redirection | 客户端必须有一些附加的动作才能完成它们的请求 |
4xx: Client Error | 此类错误应该由客户端负责 |
5xx: Server Error | 服务器对此类错误负责 |
201 Created
用于表明一个实体(Entity)被成功地创建了,例如: 创建订单的 Endpoint POST /admin/orders
,在成功创建后应该返回 201 Created
。
202 Accepted
假如电商的结账过程需要异步完成。例如: 结账操作需要异步调用货运公司的 API 才能知道运费信息。因此就需要一种异步的流程来处理。
首先,客户端先创建了一个结账(Checkout),POST /admin/checkouts
,新创建的 checkout
数据马上会返回的,但是 shipping-rate
是空的。
HTTP/1.1 202 Accepted
Content-Type: application/json; charset=utf-8
Location: https://app.mystore.com/admin/checkouts/f9604c/
Retry-After: 1
{
checkout: {
"created_at":"2016-03-18T13:21:39-04:00",
...
"shipping_rate":null,
...
}
}
此时返回的状态码是 202 Accepted
,表示数据不完整,可以后续通过“拉”操作来完成。Location
给出的是后续的“拉” API 的 Endpoint。
Retry-After
给出了“拉”的时间间隔,有两种格式。上例中单位为 “秒”,也可以跟一个期待来拉的日期时间,格式参见 HTTP Date。
连续“拉”的过程
当客户端通过去拉:
GET /admin/checkouts/f9604c/ HTTP/1.1
Host: app.mystore.com
但是仍然没有获得运费信息,那么返回内容为:
HTTP/1.1 202 ACCEPTED
Content-Type: application/json; charset=utf-8
Location: https: https://app.mystore.com/admin/checkouts/f9604c
Retry-After: 1
{
"shipping_rates": []
}
如果某次“拉”发现运费信息已经得到,那么返回的状态码就是 200 Ok
:
HTTP/1.1 200 OK
Location: https: https://app.mystore.com/admin/checkouts/f9604c
Retry-After: 1
{
"shipping_rates": [
{
"price": 10.00,
"title": "Ground",
"phone_required": false,
"delivery_range": []
}
]
}
204 No Content
有时,PUT
,POST
或者 DELETE
操作没有任何需要返回的数据,则可以直接用 204 No Content
,显示地告诉客户端没有消息体。
303 See Other
303 See Other
可以被用于一个有趣的场景。例如,你需要一口气建立一大批 checkouts。如果超过了 API 单位时间调用限制,那么则会返回 429 Too Many Requests
。但是还有一种可能是,即使没有超过调用限制,但是系统也可能将你的请求放入队列慢慢处理,此时,你就会收到 303 See Other
返回状态,以及 Location
头告诉调用者应该通过那个 URL 进行后续的轮训,使用流程类似 202 Accepted
。
400 Bad Request
如果其他 4xx 的状态码不适合表示出错原因,那么用 400 Bad Request
兜底。
401 Unauthorized
加入客户端访问某个订单数据,但是没有在 HTTP Header 中附带 User Token,那么就应该返回这个错误码。用来告诉客户端,它想访问的资源是需要先进行用户认证才能完成。
402 Payment Required
如果访问的资源超期需要续费,则返回 402 Payment Required
。例如: 用户的店铺超期未付费,那么访问该店铺所有相关的 API 都会返回这个状态。
403 Forbidden
和 401 Unauthorized
不同,403 Forbidden
是在 User Token 存在,但是权限不足以获取目标资源时返回。例如,你用 Alice 的 User Token 去访问 Bob 的订单。
404 Not Found
GET /admin/orders/{orderId}
,假如 orderId
对应的订单不存在,那么我们应该显示地返回 404 Not Found
作为状态码。
422 Unprocessable Entity (不能处理的实体)
一般发生在数据格式没有问题,但是在数据的具体的“语义”验证阶段发现问题,则返回 422 Unprocessable Entity
。 例如: 我们要创建一个订单,但是 channel
属性填写了一个未知的值。此时我们应该返回 422 Unprocessable Entity
作为 HTTP 的状态码,然后在消息体的 code
或者 error
字段提供更精准的信息。
423 Locked
如果被访问的资源被“锁”住,禁止修改和删除,可以返回此状态码。典型的例子是,订单在发货后可以被锁住,避免不小心修改。
429 Too Many Requests
这个很多人都熟悉了,用于单位时间内 API 访问次数超限。
501 Not Implemented
这个状态码往往用于今后会提供这个 API Endpoint 的有效实现,但是目前还没有,先占个坑。如果客户端不小心调了,就会返回 501 Not Implemented
。