记录一些 REST API 的常用状态码

在最近的项目中,我发现不少人在设计 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

有时,PUTPOST 或者 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

推荐阅读更多精彩内容

  • API定义规范 本规范设计基于如下使用场景: 请求频率不是非常高:如果产品的使用周期内请求频率非常高,建议使用双通...
    有涯逐无涯阅读 1,207评论 0 4
  • 关于Mongodb的全面总结 MongoDB的内部构造《MongoDB The Definitive Guide》...
    中v中阅读 18,853评论 1 73
  • 一说到REST,我想大家的第一反应就是“啊,就是那种前后台通信方式。”但是在要求详细讲述它所提出的各个约束,以及如...
    时待吾阅读 1,692评论 0 16
  • Flask之REST&API设计 一、REST(一种软件架构风格) 一)、问题 网络应用程序,分为前端和后端两个部...
    月亮是我踢弯得阅读 890评论 0 2
  • 2018/05/17农历四月初三,22年前的凌晨四点,用母亲的话说是天微微亮的时候,我的破壳之时。 天...
    We路一阅读 43评论 0 0