HTTP 协议最初的目的是为了提供一种发布和接收 HTML 页面的方法。HTTP 1.0 之前的版本,支持的 Method 只有 GET,用于获取用 URI 定义的 HTML 文件。

URI(Uniform Resource Identifiers)的含义是“统一资源定位符”,即从 HTTP 诞生之初,就是围绕着资源(Resource)进行的。

2000年 Roy Thomas Fielding 发表著名论文《架构风格与基于网络的软件设计》,被认为是首次提出了 REST(Representational State Transfer) 的概念。Fielding 本人也参与了 HTTP 的设计工作,说 HTTP 1.0/1.1 协议是 REST 的实践者一点都不过分。

在 RESTful API 设计中,重点在于如何将 WEB 应用中的万事万物都抽象为资源,这个面向对象编程是有异曲同工之妙的。

就我个人而言,第一阶段作为一个 PHP 初学者,所有操作是基于页面跳转/提交的。例如登录即先访问 /login.php,在这个页面填写一个表单,使用 POST 方法提交到 /login_post.php,在 login_post.php 有判断,成功则跳转至用户首页 /my_homepage.php,此时,在 my_homepage.php 已可以根据 PHP 内置变量 $_SESSION 查询数据库获取当前用户信息,展示丰富的页面。

这种方法很明显是非常容易把展示性页面可功能型页面混淆,而且命名及其困难。

到了第二阶段,开始使用 Ajax 传递数据(第二阶段对 SPA 和 SSR 是一样的), 依然是访问 /login.php 填写提交表单,但不再是一个页面,而是一个 API。我会写类似的 Jeuery 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$.post (
"/api/login.php",
{
username: "user1",
password: "123456"
},
function (data, status) {
if (200 <= status < 300 && data.success) {
alert("Login Success");
location.href = "/my_homepage.php";
} else {
alert("Login Field");
}
}
);

实际上,在这个阶段我们实现了一种非常非常蹩脚的 JSON-RPC 协议。RPC 的主要思想是把函数映射到 API ,对应 login.php 就应该是一个抽象函数的实例,退出登录也是一个函数 logout.php。即:

1
2
function login ($username, $password) -> Json;
function logout () -> Json;

我一开始觉得登录、注销等操作抽象为资源很困难,主要原因是 PHP 、 Python Flask 这些工具已经屏蔽了 Session 实现的细节,我并不了解登录、注销等操作的本质。

对于 HTTP 协议来说,其本身是无状态的,即使 HTTP/1.1 加入了 Connection: keep-alive,但不能做到真正的长连接。于是大家想出了很多办法来保存用户的登录状态。从最早的不靠谱的 在 URL 参数里写入 Token 实现到 Cookie 到 Storage 甚至 IndexDB。

PHP 默认使用 Cookie 实现 Session,很多 PHP 网站返回的 HTTP 报文里都会带有一个 Cookie:PHPSESSID=xxx 的 HTTP Hearder。 PHP 就是靠这个 PHPSESSID 来判断用户身份的。同时 PHP 会在服务器磁盘上留下相关文件,来持久化存储。

划重点:用户登录 = 创建标识符用户注销 = 删除标识符

这里资源即用户标识符,支持创建、删除操作

创建(登录):

1
2
3
4
5
6
7
8
POST /api/token.php HTTP/1.1
Host: exapmle.com
Content-Type: application/json

{
"username": "user1",
"password": "123456"
}
1
2
3
4
5
6
7
8
9
POST /user_access_token HTTP/1.1
Host: exapmle.com
Content-Type: application/json
Cookie:PHPSESSID=123456789

{
"msg": "登录成功",
"success": true
}

删除(注销):

1
2
3
4
5
6
7
8
9
DELETE /api/token.php HTTP/1.1
Host: exapmle.com
Content-Type: application/json
Cookie:PHPSESSID=123456789

{
"msg": "注销成功",
"success": true
}

我们也可以不使用 PHP 自带的 Seesion 功能,也可以自己实现,本文不在不说。