REST - 如何抽象為資源(Resource)

BLUICE_ZHEN發表於2018-03-07

原文發表在我的個人部落格:REST - 如何抽象為資源(Resource)

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 程式碼:

$.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。即:

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 會在伺服器磁碟上留下相關檔案,來持久化儲存。

劃重點:使用者登入 = 建立識別符號使用者登出 = 刪除識別符號

這裡資源即使用者識別符號,支援建立、刪除操作

建立(登入):

POST /api/token.php HTTP/1.1
Host: exapmle.com
Content-Type: application/json

{
    "username": "user1",
    "password": "123456"
}
複製程式碼
POST /user_access_token HTTP/1.1
Host: exapmle.com
Content-Type: application/json
Cookie:PHPSESSID=123456789

{
    "msg": "登入成功",
    "success": true
}
複製程式碼

刪除(登出):

DELETE /api/token.php HTTP/1.1
Host: exapmle.com
Content-Type: application/json
Cookie:PHPSESSID=123456789

{
    "msg": "登出成功",
    "success": true
}
複製程式碼

我們也可以不使用 PHP 自帶的 Seesion 功能,也可以自己實現,本文不在不說。

相關文章