簡單識別 RESTful 接口

jopen 9年前發布 | 19K 次閱讀 RESTful WEB服務/RPC/SOA

本文描述了識別一個接口是否真的是 RESTful 接口的基本方法。符合 REST 架構風格的接口,稱為 RESTful 接口。本文不打算從架構風格的推導方面描述,而是從 HTTP 標準的方面描述。識別的方法同時也是指導實踐的原則。


一、是否使用了正確(合適)的方法


目前對于 HTTP 標準濫用較多的,就是方法。談起 RESTful 接口的方法,很多資料告訴大家,說 GET、POST、PUT、DELETE,分別對應數據庫操作的 SELECT、INSERT、UPDATE、DELETE。其實這種理解是不正確的。


方法有兩個性質:安全性與冪等性;以及一個語義:動作本身的意思。RESTful 接口為各種數據抽象為資源,對資源的操作,主要是依據方法的兩個性質,其次才是語義。


GET 方法的語義是獲取資源,性質是安全、冪等。也就是說,對資源進行安全冪等的操作,應該用 GET 或 HEAD,當目的是獲取資源時,選用 GET,目的是獲取資源的元數據時,使用 HEAD。使用安全冪等的方法執行不安全或不冪等的操作,都是錯誤的。一個典型的例子是:


GET /book/357?op=delete


這個例子的意圖是刪除 ID 為 357 的 book,DELETE 是不安全的操作,卻使用了 GET 這個安全冪等的操作。這作法的副作用是可能被緩存,所有組件(包括搜索引擎)都認為它是安全的,從而可能不加任何限制地對它進行訪問。


POST 方法的語義是提交資源。“提交”本身就是一個比較抽象的動詞,即它的語義是可以根據環境變化的,如果將它與 INSERT 對應起來,是以偏概全的。它的性質是不安全、不冪等。這意味著所有組件對它都不緩存,不重復發送請求。執行不安全、不冪等的操作,唯有選擇 POST 方法(標準未規定的所有自定義方法,在性質上等同于 POST)。


一個不安全、不冪等的方法,可以執行安全、冪等的操作,前提是需要犧牲緩存等屬性。比如提交一個很多參數的查詢,可以使用 POST。


HTTP/1.1標準那么多年,HTML標準到5了,為什么HTML的 form 只有 GET 和 POST 兩種 action ?為沒有不把 PUT、DELETE、PATCH 等方法加進去?其實是有原因的。


首先,form 元素的提交表單的按鈕是 submit,與 POST 的語義是等同的。


其次,當瀏覽器獲得一個資源時,form 只是資源的一部分,不能表示整個資源,根據 PUT/DELETE/PATCH 的定義,它無法表示它們。


由于 POST 的性質與抽象的語義,在沒有合適的方法時,都可以使用 POST 代替。因此,將 POST 等同于新增/插入的那些文章或教材,都在誤導人。


篇幅有限,其它方法不說了,網上基于其它方法的文章基本正確的。


二、是否支使媒體協商


媒體協商是指客戶端和服務器對某種媒體類型的處理能力。一般情況下,客戶端并不知道服務器能處理哪種媒體。瀏覽器就是典型代表,它在無先驗知識的情況下,會進行媒體探測:


GET / HTTP/1.1
Host: example.com
Accept: text/html; q=1.0, image/*; q=0.8, */*; q=0.1


這是告訴服務器,我能非常有效地處理 HTML 類型的資源,圖片也是很有效的,其它的資源類型,我也能接受。于是服務器就優先按 HTML 返回資源,如果沒有 HTML 或 Image,就返回服務器自身最合適的,如 application/json。


假設服務器僅支持 application/json,當客戶端要求一個 application/xml 時,應當返回 415 Unsupported Media Type,并在正文中說明支持哪種媒體類型。


舉個值得學習的案例,Github:https://api.github.com/ ,大家可以自己試試。


三、是否能夠進行狀態轉移


這一點非常重要,也是 REST 的本意,狀態轉移!HTTP 標準實現的 REST 中,連接(Link)是實現狀態轉移的重要組件(HTML 的超鏈接和表單也是)。


在無先驗知識的前提下,客戶端請求資源 / ,這個資源及其元數據,要能夠為應用程序的下一個狀態的轉移提供必要的連接。有時候甚至要提供文檔說明的連接。


例如,當我們訪問 https://api.github.com/ 時,我們看到一個連接的列表。通過這些連接,我們的客戶端就可以跳轉到另一個狀態,從而實現整個應用程序的狀態轉移。狀態如何更好的轉移(甚至是自動化的狀態轉移),就要依賴于連接的關系(rel)以及連接的媒體類型(type)和可選的文檔。


這種狀態轉移的能力,正是 REST 的魅力。誠然,最成功的 REST 客戶端是瀏覽器,最成功的媒體類型是 text/html,最成功的 REST 是 HTTP,通過 URI 標準構建的連接,進化成我們今天無法量化的巨大的分布式系統:Web。


額外一點,一個 RESTful 的接口是不需在路徑或頭部字段中使用接口的版本號的。RESTful 接口這種說法,也有誤。REST有統一接口的概念,但這個概念一般是指 HTTP 標準。在一個 RESTful 的環境中,一切事物都是資源,資源是沒有版本號的。版本號是 API 的概念,API 是 RPC 的事物。


資源一旦發布,其結構就基本上不再發生變化。唯一能夠變化的資源結構是在對舊資源無副作用的前提下,新增資源的字段或屬性。當新增或刪除的屬性與當前資源的結構不兼容時,則需要增加一個或一類新的資源。因此,在 RESTful 實踐中,是不需要使用版本號來標識資源的。


當然,RESTful 內容的豐富,遠遠不止以上所提到的三點。但這三點是非常基本的要求。


 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!