参考:
REST 本身只是一种架构风格,并非具体标准,但 HTTP 可以认为是一份可参考的标准。正确的理解和应用的 HTTP 协议是该架构风格的一种实现,简单理解就是:HTTP 用 URI 实现了 REST 的关键概念“资源”;用 GET/POST/PUT/PATCH/DELETE 等 METHOD 实现了 REST 的另一个关键的统一接口的操作;用 status code 表示操作的结果。
当前的 RESTful API 实现 JSON over HTTP 占绝对优势地位, 若沟通中出现“REST标准”,一般指的就是这种实现。
HTTP 中的 URI 是一个树形的设计,有无限的逻辑扩展性。而 REST 本身又强调服务器是“无状态”的,正确设计的情况下,也可以带来近乎无限的物理扩展性(主要指水平扩展)。
资源是一个实体或者实体的集合(也是实体),每一种资源都有唯一并且和其它资源以相同原则组织的 URI 来标识,这个 URI 也叫 endpoint,然后在资源上使用统一的方法表达各种操作,如 POST 只是创建新资源不能用来获取资源。
如何抽象资源是业务规划的关键第一步,对业务的建模决定了我们如何看待数据、运行时模块和对它们的操作。此处的关键是:对业务的理解,开发能力和设计能力。应适当的结合并应用面向对象原则,但不宜过度。此处非常关键,这阶段的设计应有多人确认可行性。
良好抽象的资源应该是有明确而不是模棱两可定义的 URI,对 URI 定义有不易理解的部分要多加斟酌。URI 定义中的字符分割,推荐用“减号”而非下划线。
插曲:MVCC(多版本并发控制),指同一个数据实体有多个版本之别,当读时返回当前最新的版本,当有写入请求时版本更新。在读多写少的场景下,可以比全局锁等手段提升性能。唯一的冲突发生在多个并发写入请求时:A读(ver=1)-B读(ver=1)-A写(ver1->ver2)-B写(失败,它想修改的是ver1,但现在已经是ver2)。
插曲:幂等性,类似于分布式一致性的概念,可参考
METHOD 完整定义参考:,一般我们只使用五种 METHOD :
- GET :从服务器获取资源或者资源的集合,只读,幂等,无副作用。
- POST :在服务器新建一个资源,只写,有副作用,会改变资源集合。
- PUT :使用客户端数据在服务器覆盖式更新资源,并发场景建议使用 MVCC 保证一致性。
- PATCH :客户端提供部分数据,在服务器更新资源的一部分数据,同样建议在并发场景使用 MVCC 保证一致性。
- DELETE :从服务器删除资源,可选使用 MVCC。
使用正确的方法做正确的操作是容易在实现上忽略的一点,在开发过程中务必检查方法的正确性,防止一个 GET 走天下的实现。
API 实现的动作必须由 METHOD 字段体现,而不能在 URI 中体现,简单的说:URI 里尽量不要出现动词。如下是大忌:
- GET /api/v1/create-entity?id=123&name=obc
- POST /api/v1/get-entity?id=123
正确的设计应该是:
- POST /api/v1/module/entity?name=obc&unique
- GET /api/v1/module/entity/123
整体 API 的实现包括 JSON 结构定义,可读性是第一要素,尽量做到自释义。整体设计追求使用者能以最低的脑力代价无岐义的理解资源、属性、操作、分类、条件、结果等。若有可能尽量避免使用整形表达状态或类型,如type:1改成type:"udp",result:0应改成result:"success"。
若我们有一个消息服务可以这样设计:
新建一个消息,新的消息是一个资源,会有一个唯一标识。dest/clientuuid参数表示目标和客户端ID,客户端ID的作用是在重试的时候实现服务器的无状态需求:相同CID的请求被认为是重复发送,若上次已经成功执行,则不再执行动作直接返回结果。此处只接受 POST 命令,意为在消息这个集合上的操作,只有新加入。若要执行删除等操作,必须针对具体的单个消息。
- POST /api/v1/messages?dest=DEST&clientuuid=CID
获取/修改/删除 一条标识为 123456 的消息,此处消息用整形数字来标识。该消息在执行 GET 时可以通过 version 参数指定获取不同的版本。在执行修改和删除动作时,version 用来实现 MVCC 以保证幂等性。
- GET | PATCH | DELETE /api/v1/messages/123456?version=VERSION
也是新建一个消息,不同的是只发给某个用户 uid666。令牌机制(token)也是一种防止重复请求的方法,但这个 TOKEN 是服务器下发的并非客户端自己生成。可以参考:
- POST /api/v1/user/uid666/messages?token=xxxxxxxxxxx
获取某个用户的私信消息列表,参数指定开始位置和获取数量,比分页设计更容易实现服务器的无状态化。
- GET /api/v1/user/uid666/private?last=LASTID&count=COUNT
当执行完操作后,服务器务必返回能正确表达结果的状态码,若有错误需要在结果 JSON 中说明。常用状态码如:
- 200 :成功
- 201 :新资源创建成功
- 304 :资源未更改
- 400 :请求中的路径、参数或者其它错误
- 404 :资源不存在
- 500 :服务器内部错误,应该在返回的 JSON 中表达原因。
特定的状态码必须和实际情况一致,同样要避免一个 200 走天下。STATUS CODE 完整定义参考: