文前说明
作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。
本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。
1. 概述
- REST 是 Representational State Transfer 的缩写,可译为 表现层状态转化。
- 指的是一组架构约束条件和原则。
- REST 本身没有创造新的技术、组件或服务,它的理念就是在现有的技术之上,更好的使用现有的 Web 规范。
- REST 定位为 分布式超媒体应用(Distributed Hypermedia System)的架构风格。
- 假设有一个面向最终用户的 Web 应用。
- Web 应用的客户端的状态(会话状态)即 应用状态(Application State)。
- 资源在浏览器中以超媒体的形式呈现,通过点击超媒体中的链接可以获取其它相关的资源或者对当前资源进行相应的处理,获取的资源或者针对资源处理的响应同样以超媒体的形式再次呈现在浏览器上。
- 超媒体成为了驱动客户端会话状态的转换的引擎。
- 借助于超媒体这种特殊的资源呈现方式,应用状态的转换体现为浏览器中呈现资源的转换。
- 如果将超媒体进一步抽象成一般意义上的资源呈现(Representation )方式,那么应用状态变成了可被呈现的状态(Representational State)。
- 应用状态之间的转换就成了 可被呈现的状态转换(Representational State Transfer),也就是 REST。
- 假设有一个面向最终用户的 Web 应用。
- REST 是一种很笼统的概念,它代表一种架构风格。对于多个 Web 应用采用的架构,只能说其中某一个比其它的更具有 REST 风格。
2. RESTful 架构风格的特点
- REST 最大的几个特点为 资源、URI、统一接口和无状态。
2.1 资源
- 资源是网络上的一个实体,或者说是网络上的一个具体信息,可以是一段文本、一张图片、一首歌曲、一种服务,也可以是一个抽象概念,比如价值。
- 资源通过某种载体来反应其内容,文本可以通过 TXT、HTML、XML、二进制等格式表现,图片可以用 JPG 、PNG 等格式表现,JSON 是最常用的资源表现格式。
- 资源是以 JSON(或其他 Representation)为载体的、面向用户的一组数据集,资源对信息的表达倾向于概念模型中的数据。
- 资源总是以某种 Representation 为载体显示,即序列化的信息。
- Represntation 是 REST 架构的表现层。
- 最常用的 Representation 是 JSON。
- 数据(尤其是数据库)是一种更加抽象的、对计算机更高效和友好的数据表现形式,更多的存在于逻辑模型中。
2.2 URI
- 资源可以被识别,需要有个唯一标识,用一个 URI(统一资源定位符)指向资源,即每个 URI 对应一个特定的资源。
- URI 既可以看成是资源的地址,也可以看成是资源的名称。
- 要获取某个资源访问它的 URI 即可。
- 每个资源至少有一个 URI 与之对应,最典型的 URI 即 URL。
- URI 的设计应该遵循可寻址性原则,具有自描述性,需要在形式上给人以直觉上的关联。
URI 的设计技巧
- 使用 " _ " 或 " - " 增加 URI 的可读性。
- 使用 " / " 表示资源的层级关系。
- 使用 " ? " 表示资源的过滤。
- 使用 " , " 或 " ; " 表示同级资源关系。(用于分隔同级资源)
2.3 统一接口
- 应该遵循统一接口原则,统一接口包含了一组受限的预定义的操作,无论什么资源都可以通过使用相同的接口进行资源的访问。
- 数据的元操作,即 CRUD(Create、Read、Update 和 Delete)操作,分别对应 HTTP 的方法(POST、GET、PUT 和 DELETE)并遵循方法语义。
- 按照 HTTP 方法的语义来暴露资源,接口会拥有 安全性 和 幂等性 的特性。
- 安全性,对 REST 接口访问,不会使服务器端资源的状态发生改变。
- 幂等性,对同一 REST 接口的多次访问,得到的 资源状态 是相同的。
HTTP 方法 | 幂等性 | 安全性 | 说明 |
---|---|---|---|
GET | 是 | 是 | 获取资源。 |
POST | 否 | 否 | 创建子资源。 |
PUT | 是 | 否 | 用于创建和更新资源。 |
DELETE | 是 | 否 | 删除资源。 |
HEAD | 是 | 是 | 与 GET 方法类似,但不返回 message body 内容,仅仅获取资源的部分信息(content-type、content-length)。RESTful 框架中较少使用。 |
OPTIONS | 是 | 是 | 用于 URL 验证,验证接口服务是否正常。 |
TEACE | 是 | 是 | 回显服务器收到的请求,客户端可以看到(如果有)某些改变或添加已经被中间服务器实现。RESTful 框架中较少使用。 |
PATCH | 是 | 否 | 与 PUT 方法类似,代表部分更新。 |
- 根据 HTTP 规范,方法(动作)一律大写。
- 有些客户端只能使用 GET 和 POST 两种方法。服务器必须接受 POST 模拟其他方法(PUT、PATCH、DELETE 等)。
- 客户端发出的 HTTP 请求,加上 X-HTTP-Method-Override 属性,告诉服务器使用哪个方法,覆盖 POST 方法。
POST /api/Person/4 HTTP/1.1
X-HTTP-Method-Override: PUT
- HTTP 的响应码可用于应付不同场合,正确使用这些状态码意味着客户端与服务器可以在一个具备较丰富语义的层次上进行沟通。
HTTP 状态码分类
- HTTP 状态码由 3 个十进制数字组成,第 1 个十进制数字定义了状态码的类型。
分类 | 描述 |
---|---|
1** | 信息,服务器收到请求,需要请求者继续执行操作。 |
2** | 成功,操作被成功接收并处理。 |
3** | 重定向,需要进一步的操作以完成请求。 |
4** | 客户端错误,请求包含语法错误或无法完成请求。 |
5** | 服务器错误,服务器在处理请求的过程中发生了错误。 |
- API 不需要 1** 的状态码。
HTTP 状态码说明
状态码 | 英文名称 | 说明 |
---|---|---|
100 | Continue | 继续。客户端应继续其请求。 |
101 | Switching Protocols | 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到 HTTP 的新版本协议。 |
102 | Processing | 由 WebDAV(RFC 2518)扩展的状态码,代表处理将被继续执行。 |
200 | OK | 请求成功。一般用于 GET 与 POST 请求。 |
201 | Created | 已创建。成功请求并创建了新的资源。 |
202 | Accepted | 已接受。已经接受请求,但未处理完成。 |
203 | Non-Authoritative Information | 非授权信息。请求成功。但返回的 meta 信息不在原始的服务器,而是一个副本。 |
204 | No Content | 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档。 |
205 | Reset Content | 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域。 |
206 | Partial Content | 部分内容。服务器成功处理了部分 GET 请求。 |
207 | Multi-Status | 由 WebDAV(RFC 2518)扩展的状态码,代表之后的消息体将是一个 XML 消息,并且可能依照之前子请求数量的不同,包含一系列独立的响应代码。 |
300 | Multiple Choices | 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择。 |
301 | Moved Permanently | 永久移动。请求的资源已被永久的移动到新 URI,返回信息会包括新的 URI,浏览器会自动定向到新 URI。今后任何新的请求都应使用新的 URI 代替。对于某些使用 HTTP/1.0 协议的浏览器,当它们发送的 POST 请求得到了一个 301 响应的话,接下来的重定向请求将会变成 GET 方式。 |
302 | Found | 临时移动。与 301 类似。但资源只是临时被移动。客户端应继续使用原有 URI。 |
303 | See Other | 查看其它地址。与 301 类似。使用 GET 和 POST 请求查看。 |
304 | Not Modified | 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源。 |
305 | Use Proxy | 使用代理。所请求的资源必须通过代理访问。 |
306 | Unused | 已经被废弃的 HTTP 状态码。 |
307 | Temporary Redirect | 临时重定向。与 302 类似。使用 GET 请求重定向。 |
400 | Bad Request | 客户端请求的语法错误,服务器无法理解。 |
401 | Unauthorized | 请求要求用户的身份认证。 |
402 | Payment Required | 保留,将来使用。 |
403 | Forbidden | 服务器理解请求客户端的请求,但是拒绝执行此请求。 |
404 | Not Found | 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置 " 您所请求的资源无法找到 " 的个性页面。 |
405 | Method Not Allowed | 客户端请求中的方法被禁止。 |
406 | Not Acceptable | 服务器无法根据客户端请求的内容特性完成请求。 |
407 | Proxy Authentication Required | 请求要求代理的身份认证,与 401 类似,但请求者应当使用代理进行授权。 |
408 | Request Time-out | 服务器等待客户端发送的请求时间过长,超时。 |
409 | Conflict | 服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突。 |
410 | Gone | 客户端请求的资源已经不存在。410 不同于 404,如果资源以前有现在被永久删除了可使用 410 代码,网站设计人员可通过 301 代码指定资源的新位置。 |
411 | Length Required | 服务器无法处理客户端发送的不带 Content-Length 的请求信息。 |
412 | Precondition Failed | 客户端请求信息的先决条件错误。 |
413 | Request Entity Too Large | 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个 Retry-After 的响应信息。 |
414 | Request-URI Too Large | 请求的 URI 过长(URI 通常为网址),服务器无法处理。 |
415 | Unsupported Media Type | 服务器无法处理请求附带的媒体格式。 |
416 | Requested range not satisfiable | 客户端请求的范围无效。 |
417 | Expectation Failed | 服务器无法满足 Expect 的请求头信息。 |
421 | Too Many Connections | 从当前客户端所在的 IP 地址到服务器的连接数超过了服务器许可的最大范围。 |
422 | Unprocessable Entity | 请求格式正确,但是由于含有语义错误,无法响应。(RFC 4918 WebDAV) |
423 | Locked | 当前资源被锁定。(RFC 4918 WebDAV) |
424 | Failed Dependency | 由于之前的某个请求发生的错误,导致当前请求失败,例如 PROPPATCH。(RFC 4918 WebDAV) |
425 | Unordered Collection | 在 WebDav Advanced Collections 草案中定义,但是未出现在《WebDAV 顺序集协议》(RFC 3658)中。 |
426 | Upgrade Required | 客户端应当切换到 TLS/1.0。(RFC 2817) |
449 | Retry With | 由微软扩展,代表请求应当在执行完适当的操作后进行重试。 |
451 | Unavailable For Legal Reasons | 该请求因法律原因不可用。(RFC 7725) |
500 | Internal Server Error | 服务器内部错误,无法完成请求。 |
501 | Not Implemented | 服务器不支持请求的功能,无法完成请求。 |
502 | Bad Gateway | 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应。 |
503 | Service Unavailable | 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中。 |
504 | Gateway Time-out | 充当网关或代理的服务器,未及时从远端服务器获取请求。 |
505 | HTTP Version not supported | 服务器不支持请求的 HTTP 协议的版本,无法完成处理。 |
506 | Variant Also Negotiates | 由《透明内容协商协议》(RFC 2295)扩展,代表服务器存在内部配置错误。 |
507 | Insufficient Storage | 服务器无法存储完成请求所必须的内容。这个状况被认为是临时的。WebDAV (RFC 4918) |
509 | Bandwidth Limit Exceeded | 服务器达到带宽限制。这不是一个官方的状态码,但是仍被广泛使用。 |
510 | Not Extended | 获取资源所需要的策略并没有没满足。(RFC 2774) |
600 | Unparseable Response Headers | 源站没有返回响应头部,只返回实体内容。 |
2.4 无状态
- 所有的资源都可以通过 URI 定位,而且这个定位与其他资源无关,也不会因为其他资源的变化而改变。
2.5 ROA 与 SOA
- RESTful 架构风格的服务是围绕资源展开的,是典型的 ROA(Resource Oriented Architecture)架构。
- SOA(Service-Oriented Architecture)是面向服务的体系结构,是一个组件模型,将应用程序之间的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来。
ROA 的特性
- 基于 HTTP 协议,是一种明确构建在客户端/服务端体系结构上的一种风格。
- 网络上的资源都被抽象为资源,这些资源都具有唯一的统一资源标识符(URI:Uniform Resource Identiter),这些资源都是自我们描述的。这些资源使用 HTTP 内容标头类型指定。如:XML、JSON、HTML、PNG 等。
- 服务的使用者通过 HTTP 协议的标准动作(Get、Put、Post、Delete)通过统一的接口对资源进行操作。
- 对资源进行的操作不会改变 URI。
- 客户端、服务端之间的交互是没有状态的。由于这种无状态行,服务端不需要为每个客户端维护 Context。
SOA 的特征
- 通过网络终结点对外提供服务。
- 粗粒度的服务接口。
ROA 与 SOA 的共同点
- 作为服务的不同架构风格,都具有服务的一般属性。
- 统一的服务契约接口与服务接口。
- 松散的耦合。
- 只要有权限都可以进行访问。
ROA 与 SOA 的不同点
- ROA 风格下只有一种协议 HTTP。而 SOA 风格下 WCF 有多种协议。如:TCP、HTTP、MSMQ 等。
- 使用方式上的不同。ROA 只需要客户端能够模拟 HTTP 请求,通过标准的 HTTP 动作,都可以进行访问。使用的是 HTTPChannel 管道,而 SOA 使用的管道有 HTTPChannel、TcpChannel、RPC 等多种。
- ROA 寄宿时,虽然可以选择多种寄宿方式,但必须有应用服务器的支持,如 WCF。
2.6 认证机制
- RESTful 风格的服务是无状态的,认证机制尤为重要。
- 认证机制确定访问资源的用户,权限机制确定用户是否被许可使用、修改、删除或创建资源。
- 权限机制通常与服务的业务逻辑绑定,需要在每个系统内部定制。
- 认证机制基本上通用,常用的认证机制包括 session auth(即通过用户名密码登录),basic auth,token auth 和 OAuth,服务开发中常用的认证机制为后三者。
Basic Auth
- Basic Auth 是配合 RESTful API 使用的最简单的认证方式,只需提供用户名密码即可,但由于有把用户名密码暴露给第三方客户端的风险,在生产环境下被使用的越来越少。
Token Auth
- Token Auth 与 Basic Auth 的区别在于不将用户名和密码发送给服务器做用户认证,而是向服务器发送一个事先在服务器端生成的 token 来做认证。Token Auth 要求服务器端具备一套完整的 Token 创建和管理机制,该机制的实现会增加大量且非必须的服务器端开发工作,这套机制并不是足够安全和通用,因此 Token Auth用的并不多。
OAuth
- OAuth(开放授权)是一个开放的授权标准,允许用户让第三方应用访问该用户在某一 Web 服务上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。
- OAuth 允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的第三方系统(例如,视频编辑网站)在特定的时段(例如,接下来的 2 小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。OAuth 让用户可以授权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非所有内容。
- 由于 OAuth 的严谨性和安全性,OAuth 已成为 RESTful 架构风格中最常用的认证机制,和 RESTful 架构风格一起成为企业级服务的标配。
3. URL 设计
- 应该尽量将 API 部署在专用域名之下。
https://api.example.com
https://example.org/api/
- 可以将 API 的版本号放入 URL 或者 HTTP 头信息中。
https://api.example.com/v1/
- RESTful 架构中,每个网址代表一种资源(Resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。数据库中的表都是同种记录的集合(collection),所以 API 中的名词也应该使用复数。
https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees
- 对于资源的具体操作类型,由 HTTP 动词表示。
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 //删除某个指定动物园的指定动物
- 如果记录数量很多,服务器不可能将它们都返回给用户。API 应该提供参数,过滤返回结果。
?limit=10 //指定返回记录的数量
?offset=10 //指定返回记录的开始位置。
?page=2&per_page=100 //指定第几页,以及每页的记录数。
?sortby=name&order=asc //指定返回结果按照哪个属性排序,以及排序顺序。
?animal_type_id=1 //指定筛选条件
- 参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复,如下例中含义相同。
GET /zoo/ID/animals
GET /animals?zoo_id=ID
- 如果状态码是 4xx,就应该向用户返回出错信息。一般来说,返回的信息中将 error 作为键名,出错信息作为键值即可。
{
error: "Invalid API key"
}
- 针对不同操作,服务器向用户返回的结果应该符合规范。
GET /collection //返回资源对象的列表(数组)
GET /collection/resource //返回单个资源对象
POST /collection //返回新生成的资源对象
PUT /collection/resource //返回完整的资源对象
PATCH /collection/resource //返回完整的资源对象
DELETE /collection/resource //返回一个空文档
- RESTful API 最好能做到 Hypermedia,即返回结果中提供链接,向其他API方法,使得用户不查文档,也知道下一步应该做什么。
参考资料
http://www.ruanyifeng.com/blog/2018/10/restful-api-best-practices.html
https://blog.csdn.net/scrat_kong/article/details/83821203
https://www.runoob.com/w3cnote/restful-architecture.html
https://www.cnblogs.com/wang-yaz/p/9237981.html
https://blog.csdn.net/x541211190/article/details/81141459
https://www.cnblogs.com/chinajava/p/5871305.html
网友评论