SpringBoot--------Restful([夢學谷]五)

REST全稱是Representational State Transfer,中文意思是表述(編者注:通常譯爲表徵)性狀態轉移。 它首次出現在2000年Roy Fielding的博士論文中,Roy Fielding是HTTP規範的主要編寫者之一。 他在論文中提到:"我這篇文章的寫作目的,就是想在符合架構原理的前提下,理解和評估以網絡爲基礎的應用軟件的架構設計,得到一個功能強、性能好、適宜通信的架構。REST指的是一組架構約束條件和原則。" 如果一個架構符合REST的約束條件和原則,我們就稱它爲RESTful架構。

REST本身並沒有創造新的技術、組件或服務,而隱藏在RESTful背後的理念就是使用Web的現有特徵和能力, 更好地使用現有Web標準中的一些準則和約束。雖然REST本身受Web技術的影響很深, 但是理論上REST架構風格並不是綁定在HTTP上,只不過目前HTTP是唯一與REST相關的實例。 所以我們這裏描述的REST也是通過HTTP實現的REST。

2. 理解RESTful

要理解RESTful架構,需要理解Representational State Transfer這個詞組到底是什麼意思,它的每一個詞都有些什麼涵義。

下面我們結合REST原則,圍繞資源展開討論,從資源的定義、獲取、表述、關聯、狀態變遷等角度,列舉一些關鍵概念並加以解釋。

  • 資源與URI
  • 統一資源接口
  • 資源的表述
  • 資源的鏈接
  • 狀態的轉移

2. 1 資源與URI

REST全稱是表述性狀態轉移,那究竟指的是什麼的表述? 其實指的就是資源。任何事物,只要有被引用到的必要,它就是一個資源。資源可以是實體(例如手機號碼),也可以只是一個抽象概念(例如價值) 。下面是一些資源的例子:

  • 某用戶的手機號碼
  • 某用戶的個人信息
  • 最多用戶訂購的GPRS套餐
  • 兩個產品之間的依賴關係
  • 某用戶可以辦理的優惠套餐
  • 某手機號碼的潛在價值

要讓一個資源可以被識別,需要有個唯一標識,在Web中這個唯一標識就是URI(Uniform Resource Identifier)。

URI既可以看成是資源的地址,也可以看成是資源的名稱。如果某些信息沒有使用URI來表示,那它就不能算是一個資源, 只能算是資源的一些信息而已。URI的設計應該遵循可尋址性原則,具有自描述性,需要在形式上給人以直覺上的關聯。這裏以github網站爲例,給出一些還算不錯的URI:

  • https://github.com/git
  • https://github.com/git/git
  • https://github.com/git/git/blob/master/block-sha1/sha1.h
  • https://github.com/git/git/commit/e3af72cdafab5993d18fae056f87e1d675913d08
  • https://github.com/git/git/pulls
  • https://github.com/git/git/pulls?state=closed
  • https://github.com/git/git/compare/master…next

下面讓我們來看看URI設計上的一些技巧:

  • 使用_或-來讓URI可讀性更好

曾經Web上的URI都是冰冷的數字或者無意義的字符串,但現在越來越多的網站使用_或-來分隔一些單詞,讓URI看上去更爲人性化。 例如國內比較出名的開源中國社區,它上面的新聞地址就採用這種風格, 如http://www.oschina.net/news/38119/oschina-translate-reward-plan。

  • 使用/來表示資源的層級關係

例如上述/git/git/commit/e3af72cdafab5993d18fae056f87e1d675913d08就表示了一個多級的資源, 指的是git用戶的git項目的某次提交記錄,又例如/orders/2012/10可以用來表示2012年10月的訂單記錄。

  • 使用?用來過濾資源

很多人只是把?簡單的當做是參數的傳遞,很容易造成URI過於複雜、難以理解。可以把?用於對資源的過濾, 例如/git/git/pulls用來表示git項目的所有推入請求,而/pulls?state=closed用來表示git項目中已經關閉的推入請求, 這種URL通常對應的是一些特定條件的查詢結果或算法運算結果。

  • ,或;可以用來表示同級資源的關係

有時候我們需要表示同級資源的關係時,可以使用,或;來進行分割。例如哪天github可以比較某個文件在隨意兩次提交記錄之間的差異,或許可以使用/git/git /block-sha1/sha1.h/compare/e3af72cdafab5993d18fae056f87e1d675913d08;bd63e61bdf38e872d5215c07b264dcc16e4febca作爲URI。 不過,現在github是使用…來做這個事情的,例如/git/git/compare/master…next。

2. 2 統一資源接口

RESTful架構應該遵循統一接口原則,統一接口包含了一組受限的預定義的操作,不論什麼樣的資源,都是通過使用相同的接口進行資源的訪問。接口應該使用標準的HTTP方法如GET,PUT和POST,並遵循這些方法的語義。

如果按照HTTP方法的語義來暴露資源,那麼接口將會擁有安全性和冪等性的特性,例如GET和HEAD請求都是安全的, 無論請求多少次,都不會改變服務器狀態。而GET、HEAD、PUT和DELETE請求都是冪等的,無論對資源操作多少次, 結果總是一樣的,後面的請求並不會產生比第一次更多的影響。

下面列出了GET,DELETE,PUT和POST的典型用法:

GET

  • 安全且冪等
  • 獲取表示
  • 變更時獲取表示(緩存)
  • 200(OK) - 表示已在響應中發出
  • 204(無內容) - 資源有空表示
  • 301(Moved Permanently) - 資源的URI已被更新
  • 303(See Other) - 其他(如,負載均衡)
  • 304(not modified)- 資源未更改(緩存)
  • 400 (bad request)- 指代壞請求(如,參數錯誤)
  • 404 (not found)- 資源不存在
  • 406 (not acceptable)- 服務端不支持所需表示
  • 500 (internal server error)- 通用錯誤響應
  • 503 (Service Unavailable)- 服務端當前無法處理請求

POST

  • 不安全且不冪等
  • 使用服務端管理的(自動產生)的實例號創建資源
  • 創建子資源
  • 部分更新資源
  • 如果沒有被修改,則不過更新資源(樂觀鎖)
  • 200(OK)- 如果現有資源已被更改
  • 201(created)- 如果新資源被創建
  • 202(accepted)- 已接受處理請求但尚未完成(異步處理)
  • 301(Moved Permanently)- 資源的URI被更新
  • 303(See Other)- 其他(如,負載均衡)
  • 400(bad request)- 指代壞請求
  • 404 (not found)- 資源不存在
  • 406 (not acceptable)- 服務端不支持所需表示
  • 409 (conflict)- 通用衝突
  • 412 (Precondition Failed)- 前置條件失敗(如執行條件更新時的衝突)
  • 415 (unsupported media type)- 接受到的表示不受支持
  • 500 (internal server error)- 通用錯誤響應
  • 503 (Service Unavailable)- 服務當前無法處理請求

PUT

  • 不安全但冪等
  • 用客戶端管理的實例號創建一個資源
  • 通過替換的方式更新資源
  • 如果未被修改,則更新資源(樂觀鎖)
  • 200 (OK)- 如果已存在資源被更改
  • 201 (created)- 如果新資源被創建
  • 301(Moved Permanently)- 資源的URI已更改
  • 303 (See Other)- 其他(如,負載均衡)
  • 400 (bad request)- 指代壞請求
  • 404 (not found)- 資源不存在
  • 406 (not acceptable)- 服務端不支持所需表示
  • 409 (conflict)- 通用衝突
  • 412 (Precondition Failed)- 前置條件失敗(如執行條件更新時的衝突)
  • 415 (unsupported media type)- 接受到的表示不受支持
  • 500 (internal server error)- 通用錯誤響應
  • 503 (Service Unavailable)- 服務當前無法處理請求

DELETE

  • 不安全但冪等
  • 刪除資源
  • 200 (OK)- 資源已被刪除
  • 301 (Moved Permanently)- 資源的URI已更改
  • 303 (See Other)- 其他,如負載均衡
  • 400 (bad request)- 指代壞請求
  • 404 (not found)- 資源不存在
  • 409 (conflict)- 通用衝突
  • 500 (internal server error)- 通用錯誤響應
  • 503 (Service Unavailable)- 服務端當前無法處理請求

下面我們來看一些實踐中常見的問題:

  • POST和PUT用於創建資源時有什麼區別?

POST和PUT在創建資源的區別在於,所創建的資源的名稱(URI)是否由客戶端決定。 例如爲我的博文增加一個java的分類,生成的路徑就是分類名/categories/java,那麼就可以採用PUT方法。不過很多人直接把POST、GET、PUT、DELETE直接對應上CRUD,例如在一個典型的rails實現的RESTful應用中就是這麼做的。

我認爲,這是因爲rails默認使用服務端生成的ID作爲URI的緣故,而不少人就是通過rails實踐REST的,所以很容易造成這種誤解。

  • 客戶端不一定都支持這些HTTP方法吧?

的確有這種情況,特別是一些比較古老的基於瀏覽器的客戶端,只能支持GET和POST兩種方法。

在實踐上,客戶端和服務端都可能需要做一些妥協。例如rails框架就支持通過隱藏參數_method=DELETE來傳遞真實的請求方法, 而像Backbone這樣的客戶端MVC框架則允許傳遞_method傳輸和設置X-HTTP-Method-Override頭來規避這個問題。

  • 統一接口是否意味着不能擴展帶特殊語義的方法?

統一接口並不阻止你擴展方法,只要方法對資源的操作有着具體的、可識別的語義即可,並能夠保持整個接口的統一性。

像WebDAV就對HTTP方法進行了擴展,增加了LOCK、UPLOCK等方法。而github的API則支持使用PATCH方法來進行issue的更新,例如:

PATCH /repos/:owner/:repo/issues/:number

不過,需要注意的是,像PATCH這種不是HTTP標準方法的,服務端需要考慮客戶端是否能夠支持的問題。

  • 統一資源接口對URI有什麼指導意義?

統一資源接口要求使用標準的HTTP方法對資源進行操作,所以URI只應該來表示資源的名稱,而不應該包括資源的操作。

通俗來說,URI不應該使用動作來描述。例如,下面是一些不符合統一接口要求的URI:

  • GET /getUser/1
  • POST /createUser
  • PUT /updateUser/1
  • DELETE /deleteUser/1

如果GET請求增加計數器,這是否違反安全性?

安全性不代表請求不產生副作用,例如像很多API開發平臺,都對請求流量做限制。像github,就會限制沒有認證的請求每小時只能請求60次。

但客戶端不是爲了追求副作用而發出這些GET或HEAD請求的,產生副作用是服務端"自作主張"的。

另外,服務端在設計時,也不應該讓副作用太大,因爲

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章