近些年,随着WEB应用中,业务逻辑被越来越多地移到客户端,服务器的主要功能(有时是唯一功能)是为客户端提供数据存取服务。在这种模式中,服务器变成了Web服务或应用编程接口(API)。在编写API时,表现层状态转移(REST)架构崭露头角。Flask是开发REST架构的理想框架,因为Flask天生轻量。本章我们将学习如何使用Flask实现符合REST架构的API。
一. REST简介
REST架构具有如下特征:
- 客户端-服务器:客户端和服务器之间必须有明确的界限;
- 无状态:客户端发出的请求中必须包含所有必要的信息,服务器不能在2次请求之间保存客户端的任何状态;
- 缓存:服务器发出的响应可标记为可缓存或不可缓存,这样出于优化目的,客户端(客户端和服务器之间的中间服务)可以进行缓存;
- 接口统一:客户端访问服务器资源时使用的协议必须一致、定义良好,且已经标准化。这是REST架构最复杂的一方面,涉及唯一的资源标识符、资源表述、客户端和服务器之间自描述的消息,以及超媒体(当序列化返回的资源中包含相关链接和自身描述信息的资源被称为超媒体,因为这些数据在被机器解析时可以像人类浏览网页一样对资源进行进一步的操作);
- 系统分层:在客户端和服务器之间可以按需插入代理服务器、缓存和网关,以提高性能、稳定性和伸缩性。
- 按需编程:客户端可以选择从服务器中下载代码,在客户端上下文中执行。
二. 资源就是一切
资源是REST架构风格的核心概念,比如博客应用中的用户、文章和评论都是资源。每个资源都要使用唯一的URL表示,比如一篇博客文章的URL可以是:/api/posts/12345,其中12345是这片文章的唯一标志符,使用文章在数据库中的主键表示。某一类资源的集合也要有一个URL,如博客文章集合的URL可以是/api/posts/,评论集合的URL可以是/api/comments/。
API还可以为某一类资源的逻辑子集定义集合URL。例如:编号为12345的博客文章,其所有评论可以使用URL:/api/posts/12345/comments/表示。表示资源集合的URL习惯在末端加上一个斜线,代表一种“子目录”结构。
注:Flask会特殊对待末端带有斜线的路由。如果客户端请求的URL没有斜线,而唯一匹配的路由带有斜线,Flask会自动响应一个重定向,转向末端带有斜线的URL。
三. 请求方法
REST式API常用的HTTP方法
请求方法 | 目标 | 说明 | HTTP状态码 |
GET | 单个资源的URL | 获取目标资源 | 200 |
GET | 资源集合的URL | 获取资源的集合(如果服务器实现了分页,还可以是一页中的资源) | 200 |
POST | 资源集合的URL | 创建新资源,并将其加入目标集合。服务器为新资源指派URL,并在响应的Location首部中返回; | 201(请求成功,而且创建了一个新资源) |
PUT | 单个资源的URL | 修改一个现有资源。 | 200或204(成功处理,但返回的响应没有数据) |
DELETE | 单个资源的URL | 删除一个资源 | 200或204 |
DELETE | 资源集合的URL | 删除目标集合中的所有资源 | 200或204 |
四. 请求和响应主体
在请求和响应的主体中,资源在客户端和服务器之间来回穿送,但REST并没有指定编码资源的方式。请求和响应中的Content-Type首部用于指明主体中资源的编码方式,使用HTTP协议的内容协商机制,可以找到一种客户端和服务器都支持的编码方式。
REST式WEB服务常用的编码方式是JSON和XML。其中JOSN使用更为广泛,因为JSON比XML简洁,而且与WEB浏览器使用的客户端脚本语言JS联系密切。比如,一篇博客文章对应的资源可以用如下JSON表示:
{
"self_url": "http://www.example.com/api/posts/12345",
"title": "xxxxxxxxxxxxxxxxxxxx",
"author_url": "http://www.example.com/api/user/2",
"body": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"comments_url": "http://www.example.com/api/posts/12345/comments"
}
注意:self_url、author_url、comments_url都是完整的资源URL。这是很重要的表示方法,因为客户端可以通过这些URL发觉新资源。在设计良好的REST API中,客户端只需要知道几个顶级资源的URL,其它资源的URL则从响应中包含的链接上发掘。这就好比浏览网络时,你在自己知道的网页中点击链接发现新网页一样。
五. 版本
在传统以服务器为中心的WEB应用中,服务器完全掌控应用。更新应用时,只需要在服务器上部署新版本就可更新所有用户。但对于WEB服务而言,有很多客户端在使用,其中包括浏览器和智能手机原生应用。当WEB服务升级时,无法将所有客户端也同步升级。这一问题常见的处理办法是使用版本区分WEB服务所处理的URL。带到旧版本的客户端都升级后,再讲旧版本的WEB服务移除。