1

1. 说明

REST(Representational State Transfer)指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。

目前的三种主流 Web 服务实现方式——远程过程调用(RPC),面向服务架构(SOA)以及表述性状态转移(REST),REST 方式与复杂的 SOAP 和 XML-RPC 比起来更加简洁,越来越多的 Web 服务开始采用 REST 风格设计和实现。例如,Amazon.com 提供接近 REST 风格的 Web 服务进行图书查找;雅虎提供的 Web 服务也是 REST 风格的。

远程过程调用(RPC)

远程过程调用为 Web 服务提供一个分布式函数/方法接口供用户调用。这是一种较传统的方式。通常,在 WSDL 中对 RPC 接口进行定义(类似于早期的XML-RPC)。本质上,RPC 方式利用一个简单映射,把用户请求直接转化成一个特定语言编写的函数/方法。现在,该方式已不再使用。

面向服务架构(SOA)

面向服务架构现在,业界比较关注的是遵从面向服务架构(Service-oriented architecture,SOA)来构建 Web 服务。该方式中,通讯是由消息驱动,而不再是某个动作(方法调用)。这种 Web 服务也称为“面向消息的服务”。

表述性状态转移(REST)

REST是从资源角度来观察整个网络,资源由通用资源标志符(Uniform Resource Identifier,URI)确定,客户端应用通过 URI 获取资源的表征,这些表征会使应用程序转变其状态。随着不断地获得资源表征,客户端应用也不断地转变其状态。

在我们当前开发中,绝大多数应用场景都是建议使用REST规范的,所以建议项目上的API设计,都要默认遵循RESTful风格。

2. HTTP协议

对于HTTP协议,我们既熟悉,又陌生。熟悉,是因为我们每天开发API服务,都是基于HTTP协议。陌生,是因为我们大多数人在API设计上,都没有完全考虑到HTTP协议的规范。

!>HTTP是基于客户端/服务端(C/S)的架构模型,通过一个可靠的链接来交换信息,是一个无状态的请求/响应协议。HTTP使用统一资源标识符(Uniform Resource Identifiers, URI)来传输数据和建立连接。

一个基于HTTP协议消息,由如下部分组成:

  1. HTTP请求方法:HTTP1.0只有GET、POST、HEAD,HTTP1.1之后增加OPTIONS、PUT、PATCH、DELETE、CONNECT等。
  2. HTTP响应头:提供了关于请求,响应或者其他的发送实体的信息。
  3. HTTP状态码:HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。1xx(信息,服务器收到请求,需要请求者继续执行操作)、2xx(成功,操作被成功接收并处理)、3xx(重定向,需要进一步的操作以完成请求)、4xx(客户端错误,请求包含语法错误或无法完成请求)、5xx(服务器错误,服务器在处理请求的过程中发生了错误)。
  4. content-type:告诉客户端实际返回的内容的内容类型。

我们来看一段HTTP GET请求和响应的报文:

请求报文

GET /users HTTP/1.1
uid: Kerry
User-Agent: PostmanRuntime/7.24.0
Accept: */*
Cache-Control: no-cache
Postman-Token: 4f23c891-9279-4e89-85c9-329b7c47262a
Host: localhost:8002
Accept-Encoding: gzip, deflate, br
Connection: keep-alive


响应报文

HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 26 Mar 2020 07:46:29 GMT
Keep-Alive: timeout=60
Connection: keep-alive
[{"id":41,"username":"Kerry","chinese_name":"吴晨瑞0329","email":"kerry.wu@definesys.com","birthday":"1995-08-18","department_id":1,"object_version":4,"created_by":"Kerry","created_date":"2020.03.08 18:15:14","last_updated_by":"kerry0325","last_updated_date":"2020.03.26 14:38:57","department_name":null}]

关于HTTP协议的详细介绍,建议查看菜鸟教程。

3. URL路径

路径又称"终点"(endpoint),表示API的具体网址。

  1. 服务器层面上,建议将API部署在专用域名之下,或主域名下。如:https://api.example.comhttps://example.org/api/
  2. 建议将API的版本号放入URL中,如:https://api.example.com/v1/ 。另一种做法是,将版本号放在HTTP头信息中,但不如放入URL方便和直观。Github采用这种做法。直接修改线上接口,会导致调用方报错,建议通过升版本号实现。
  3. 在RESTful架构中,每个网址代表一种资源,所以网址中不能有动词,只能有名词。名词可以是与数据库的表格名对应,也可以是与业务系统,或业务功能名称对应。
  4. 如果名词是与数据库的表格名对应的,API中的名词应该使用复数,其他情况则没必要。
  5. 按照资源的逻辑层级,对 URL 进行嵌套。
  6. 路径中的资源名称一律使用小写字母,如果名词由多个单词组成,则使用连字符”-“来连接单词。
  7. API参数传递时,无论是基于path还是body,参数命名都统一用驼峰式命名。

    举个经典的例子,有一个API提供动物园(zoo)的信息,还包括各种动物园里面动物的信息,则它的GET接口路径应该设计成下面这样。

    <!-- 查询所有动物园信息 -->
    https://api.example.com/v1/zoo-mg/zoos
    
    <!-- 查询某个{ID}动物园的所有动物信息 -->
    https://api.example.com/v1/zoo-mg/zoos/{ID}/animals 
    
    <!-- 分页查询某个{ID}动物园的猫科动物信息 -->
    https://api.example.com/v1/zoo-mg/zoos/{ID}/animals?class=猫科&page=1&pageSize=10
    

4. HTTP动词

对于资源的具体操作类型,由HTTP动词表示。

常用的HTTP动词有下面五个(括号里是对应的SQL命令)。

  • GET(SELECT):从服务器取出资源(一项或多项)。
  • POST(CREATE):在服务器新建一个资源。
  • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
  • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
  • DELETE(DELETE):从服务器删除资源。

还有两个不常用的HTTP动词。

  • HEAD:获取资源的元数据。
  • OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。

下面是一些例子。

  • GET /zoos:列出所有动物园
  • POST /zoos:新建一个动物园
  • GET /zoos/ID:获取某个指定动物园的信息
  • PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
  • PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
  • DELETE /zoos/ID:删除某个动物园
  • GET /zoos/ID/animals:列出某个指定动物园的所有动物
  • DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

5. 接口返回

1 成功

状态码

状态码为2xx,这里建议都用200返回。

响应结果

针对不同操作,服务器向用户返回的结果应该符合以下规范。

  • GET /collection:返回资源对象的列表(数组)
  • GET /collection/resource:返回单个资源对象
  • POST /collection:返回新生成的资源对象
  • PUT /collection/resource:返回完整的资源对象
  • PATCH /collection/resource:返回完整的资源对象
  • DELETE /collection/resource:返回一个空文档

2 失败

状态码

状态码有 4xx 或 5xx ,如:500 INTERNAL SERVER ERROR、401 Unauthorized、404 NOT FOUND等。

响应结果

对于需要向用户返回出错信息的。我们定义,在返回的信息中将error作为键名,出错信息作为键值即可。

{
    "error": "告知用户的错误原因"
}

KerryWu
641 声望159 粉丝

保持饥饿