RESTful Web 服務:教程

RESTful Web 服務:教程
 

隨着 REST 成爲大多數 Web 和 Mobile 應用的默認選擇,勢必要對它的基本原理有所瞭解。html

在它提出十多年後的今天,REST 已經成爲最重要的 Web 應用技術之一。隨着全部技術朝着 API 方向發展,它的重要性有可能持續快速地增加。每門主要編程語言如今已經包含構建 RESTful Web 服務的框架。一樣地,Web 開發者和架構師對 REST 和 RESTful 服務有一個清晰的理解是很重要的。這篇教程解釋了 REST 架構,而後研究使用它構建通用地基於API的任務的細節。前端

什麼是 REST

REST 表明表述性狀態轉移(representational state transfer),它是一種網絡化超媒體應用的架構風格。它主要是用於構建輕量級的、可維護的、可伸縮的 Web 服務。基於 REST 的服務被稱爲 RESTful 服務。REST 不依賴於任何協議,可是幾乎每一個 RESTful 服務使用 HTTP 做爲底層協議。java

RESTful 使用HTTP post(建立、更新)數據、讀取數據、刪除數據。使用HTTP實現CRUD(建立、讀取、更新、刪除)操做。react

RESTful 服務特色:

每一個系統都使用資源。這些資源能夠是圖片,視頻文件,網頁,商業信息,或者在基於計算機的系統中能夠被表明的任何事物。服務的目的是提供一個窗口給客戶端以便客戶端能訪問這些資源。服務架構師和開發人員想要這些服務變得易於實現、維護、擴展、伸縮。RESTful 架構容許這些,甚至更多。通常來講,RESTful 服務應該有下面的屬性和特徵,也就是我要詳細描述的內容:git

  • 模型表示(Representations)
  • 消息(Messages)
  • URIs
  • 一致接口(Uniform interface)
  • (無狀態)Stateless
  • 資源之間的連接(Links between resources)
  • 緩存(Caching)

模型表示(Representations)

RESTful 服務的焦點在資源上和怎麼提供對資源的訪問。資源很容易被認爲和OOP中的對象同樣。一個資源能由其餘資源組成。當設計一個系統的時候,第一件要作的事情是定義資源和決定資源之間的關係。這有點像設計數據庫的第一步。定義實體和關係。github

一旦咱們定義了資源,接下來咱們須要找到一種用於在系統中表示這些資源的方法。你可使用任何格式來表示資源。REST 對此沒有限制。web

例如,根據你的需求,你能夠決定使用 JSON 或者 XML。若是你在構建 Web 服務,此服務用於 Web 頁面中的 AJAX 調用,那 JSON 是很好地選擇。 XML 能夠用來表示比較複雜的資源。例如一個被稱爲「Person」的資源能夠表示以下:數據庫

列表1:資源的JSON 表示。

{
    "ID": "1",
    "Name": "M Vaqqas",
    "Email": "m.vaqqas@gmail.com",
    "Country": "India"
}

列表2:資源的XML 表示。

<Person>
	<ID>1</ID>
	<Name>M Vaqqas</Name>
	<Email>m.vaqqas@gmail.com</Email>
	<Country>India</Country>
</Person>

實際上,你可使用不止一種的格式而且決定使用其中哪種用於依賴於客戶端類型或一些請求參數的響應。不管使用哪一個格式,好的模型表示(representation )應該具備如下明顯的特徵:編程

  • 客戶端和服務端應該可以理解這種模型表示(representation )的格式。
  • 模型表示(representation )應該可以完整的表示資源。若是須要表示部分資源,而後你須要考慮將資源分解成子資源。分割大資源到更小的資源一樣容許你傳遞更小的表現。較小的模型表示(representation)意味着更少的時間來建立和傳輸。這也意味着更快的服務。
  • 模型表示(representation)應該可以互相連接資源。能夠經過替換 URI 或者是惟一 ID。

消息(Messages)

客戶端和服務端經由消息相互溝通。客戶端發送請求到服務器,服務器使用響應答覆。除了實際的數據,這些信息也包含一些關於消息的元數據。對於設計 RESTful 服務瞭解 HTTP 1.1的請求格式和響應格式是很重要的。json

HTTP 請求

圖1中展現了HTTP請求格式。

圖1:HTTP 請求格式

<VERB> GET, PUT, POST, DELETE, OPTIONS等等 HTTP 方法的一種。

<URI> 資源的URI。操做將在這個 URI 上執行。

<HTTP Version> HTTP 版本,一般是「HTTP v1.1」。

<Request Header> 包含 header 鍵值對集合的元數據。這些設置包含消息的信息和發送者像客戶端的類型,客戶端支持的格式,消息體的格式類型,響應的緩存設置,和許多信息。

<Request Body> 是實際的消息內容。在 RESTful 服務中,這就是消息中資源表示的位置。

在 HTML 消息中沒有標籤和標識標記區塊的開始或結束。

列表三是簡單的 POST 請求消息,這個請求想要插入一條新的 Person 資源。

列表3:簡單 POST 請求

POST http://MyService/Person/
Host: MyService
Content-Type: text/xml; charset=utf-8
Content-Length: 123
<?xml version="1.0" encoding="utf-8"?>
<Person>
  <ID>1</ID>
  <Name>M Vaqqas</Name>
  <Email>m.vaqqas@gmail.com</Email>
  <Country>India</Country>
</Person>

列表4:GET 請求

GET http://www.w3.org/Protocols/rfc2616/rfc2616.html HTTP/1.1
Host: www.w3.org
Accept: text/html,application/xhtml+xml,application/xml; …
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 …
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,hi;q=0.6

HTTP Response

圖2展現了 HTTP 響應的格式:

圖2:HTTP 響應格式。

服務器返回 <response code>,<response code>包含請求的狀態。<response code>一般是三位數字的HTTP狀態碼(3-digit HTTP status code)。

<Response Header> 包含關於響應消息的元數據和設置。

<Response Body> 包含若是請求成功的模型表示(representation)。

列表5是我從清單三的請求中獲得的真實響應。

列表5:真實的 GET 請求的響應。

HTTP/1.1 200 OK
Date: Sat, 23 Aug 2014 18:31:04 GMT
Server: Apache/2
Last-Modified: Wed, 01 Sep 2004 13:24:52 GMT
Accept-Ranges: bytes
Content-Length: 32859
Cache-Control: max-age=21600, must-revalidate
Expires: Sun, 24 Aug 2014 00:31:04 GMT
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns='http://www.w3.org/1999/xhtml'>
<head><title>Hypertext Transfer Protocol -- HTTP/1.1</title></head>
<body>
...

響應碼 200 OK 表示一切正常,而且消息體包含我請求的有效的模型表示(representation)。在這個例子中,模型表示(representation)是 HTML 文檔,HTML 文檔是經過在響應頭中的 Content-Type 聲明地。在這個消息中的 header 是不解自明地,可是我將會在接下來的文章中討論他們中的一些。這有不少其餘屬性。你可使用叫Fiddle的免費工具抓取調試這些HTTP請求和響應。

資源定位

REST 要求每一個資源至少有一個 URI。 RESTful 服務使用人類可讀的URIs層級目錄來定位資源。URI 要作的工做是定義一個資源或資源集合。實際的操做由 HTTP 動做決定。URI 應該沒有任何關於處理和動做的內容。這使咱們可以調用相同的 URI 使用不一樣的 HTTP 動詞來執行不一樣的操做。

假設咱們有一個 person 的數據庫而且咱們但願經過服務器暴露給外部。Person 資源能夠像下面這樣被定位到:

MyService/Persons/1

此URL遵循格式:Protocol://ServiceName/ResourceType/ResourceID

對於構建良好的 URIs 這有些重要的推薦:

  • 使用複數名詞命名你的資源。
  • 避免使用製造混亂的空格。使用_或者-代替。
  • URI 不區分大小寫。爲了更清晰我使用駝峯寫法。你也可使用所有小寫的URIs。
  • 你也可以有你本身的約定,可是要在整個服務保持一致。確保你的客戶端都知道這個約定。你的客戶端 URIs 程序構建將更簡單若是它們知道你遵循的資源層級和URI約定。
  • 好的 URI 是不會變動的。再決定服務的 URIs 以前要先思考思考。若是你須要改變資源的定位,不要放棄老的 URI。若是請求來自老的 URI,使用狀態碼300重定向客戶端到新的location。
  • 避免使用動詞命名你的資源直到你的資源是一個實際地操做或過程。動詞更加適合操做的命名。例如,RESTful 服務不該該有 MyService/FetcthPerson/MyService/DeletePerson? 相似的 URI。

URI中的查詢參數

前面的URI是用查詢參數幫助構建的。

MyService/Persons?

查詢參數方法運行良好並且 REST 不會阻止你使用查詢參數。然而,這種方式有一些劣勢:

  • 增長了複雜性,下降了可讀性。若是你使用更多的參數問題會更加明顯。
  • 像Google這樣的搜索引擎爬網程序和索引器忽略uri查詢參數。若是你正在進行Web開發,這是你的Web服務一部分很大的劣勢,致使搜索引擎屏蔽。

查詢參數的基本目的是提供參數給須要的數據項的操做。例如,若是你想要模型表示(presentation)格式由客戶端決定,你能夠經過參數實現像下面這樣。

MyService/Persons/1?

MyService/Persons/1?

包含format和encoding參數的父子層級URI看上去邏輯上不正確由於它們沒有這種關係。

MyService/Persons/1/jso

查詢參數也容許可選參數。在URI中顯然是不可能的。你僅僅應該在提供參數值給處理過程的時候使用。

統一接口

RESTful應該有統一接口。HTTP 1.1 提供了一系列方法,被稱爲動做。在這其中比較重要的動做是:

安全的操做是指對原始資源值不會產生影響的操做。列如,數學上的操做除以1就是安全的操做,由於不管多少次用1除一個數,原始數值都不會改變。冪等操做是指不管多少次執行都給出相同結果的操做。例如,數學上的乘以0就是冪等的,由於不管計算多少次結果都是零,結果都是同樣的。相似的,一個安全的HTTP方法不會使服務器上的資源發生變化。一個冪等的HTTP方法不管執行多少次都會有相同的響應。把方法分類成安全和冪等的可使客戶端在不穩定的Web環境中再次觸發相同的請求的結果變得更可預測。

在 Web 上 GET 多是最流行的方法。它用來獲取資源。

HEAD 僅返回響應頭和空的響應體。這個方法能夠用在你不須要所有的資源模型表示(representation)的時候。例如,HEAD 能夠快速檢測服務器上的資源是否存在。

OPTIONS 用於獲取資源容許的操做。例如,思考下面的請求:

OPTIONS http://MyService/Persons/1 HTTP/1.1
HOST: MyService

在服務驗證以後請求返回下面內容:

200 OK
Allow: HEAD, GET, PUT

第二行包含客戶端可使用的方法。

你應該僅僅出於它們的實際意義使用這些方法。例如:毫不要使用 GET 在服務器上建立或刪除資源。若是你沒這樣作,將會擾亂你的客戶端致使他們作出意外的操做。舉例說明,然咱們考慮下面的請求:

GET http://MyService/DeletePersons/1 HTTP/1.1
HOST: MyService

根據 HTTP 1.1 規範,GET 請求的目的是從服務器獲取資源。可是它很容易實現一個刪除 Person 的請求。這個請求也許運行的很棒,可是這不是RESTful 設計。換言之,使用 DELETE 方法來刪除資源像下面這樣:

DELETE http://MyService/Persons/1 HTTP/1.1
HOST: MyService

REST 建議統一接口,HTTP 提供了統一接口。然而,這由服務架構師和開發人員保持它的統一。

PUT 和 POST 的區別

對於這兩個方法我提供了幾乎相同的簡短描述。這兩個方法困擾着許多開發人員。因此讓咱們單獨地討論他們。

PUT 和 POST 的關鍵不一樣在於 PUT 是冪等的,而 POST 不是。

另外一個不一樣,使用 PUT 你須要定義資源完整的 URI。這意味着客戶端能構造資源的URI哪怕資源不存在於服務器上。客戶端選擇資源惟一的名字或 ID 是可能的。就像在服務器上建立一個用戶須要客戶端選擇用戶 ID。若是客戶端不能猜想出資源完整的URI,你別無選擇,只能使用 POST。

很明顯,PUT 請求不會修改或建立超過一個資源,不管觸發多少次(若是URI相同)。當資源存在時 PUT 和 POST 是沒有區別的,都是更新已存在資源。第三個請求(POST MyService/Persons/)會在每次觸發都建立資源。許多開發人員認爲 REST 不容許 POST 被用於更新操做。然而,REST 並無這樣的限制。

無狀態

RESTful 服務是無狀態的而且不會爲任何客戶端保持狀態。一個請求不該該依賴過去的請求,服務對待每一個請求都是獨立的。HTTP 是無狀態協議的設計,你須要作一些額外的事情實現狀態服務。使用當前的技術真的很容易實現狀態服務。咱們須要清楚的理解無狀態和有狀態設計以便咱們避免誤解。

無狀態設計像這樣:

Request1: GET MyService/Persons/1 HTTP/1.1

Request2: GET MyService/Persons/2 HTTP/1.1

每一個請求都能被單獨對待。

有狀態設計,像這樣:

Request1: GET MyService/Persons/1 HTTP/1.1

Request2: GET MyService/NextPerson HTTP/1.1

爲了處理第二個請求,服務器須要記住客戶端最後獲取的 PersonID。換句話說,服務器須要記住當前狀態————不然請求2沒法處理。設計你的服務的方式是一個請求毫不要涉及前一個請求。無狀態服務更容易集羣,更容易維護,更容易伸縮。這樣的服務提供了更好的響應時間,由於它們能容易的負載均衡。

資源之間的連接

資源模型表示(representation )能夠包含其餘資源的連接就像 HTML 頁面包含到其餘頁面的連接同樣。被服務返回的模型表示(representations )應該能驅動處理流就像網站的狀況同樣。當訪問網站的時候,首先是索引頁面,單擊其中的一個連接跳轉到另一個頁面等等。

讓咱們考慮下客戶端請求一個包含許多其餘資源的資源。替代輸入全部資源,你可能會列出資源的連接。

例如,若是多個Person是Club的一部分,那麼Club能像列表6中同樣表示。

列表6:Club

<Club>        
	<Name>Authors Club</Name>
	<Persons>
		<Person>
			<Name>M. Vaqqas</Name>
			<URI>http://MyService/Persons/1</URI>
		</Person>
		<Person>
			<Name>S. Allamaraju</Name>
			<URI>http://MyService/Persons/12</URI>
		</Person>
	</Persons>
</Club>

緩存

緩存是存貯生成結果的概念,使用存儲結果替代在不久的未來重複的請求生成的結果。緩存能夠在客戶端、服務端或者他們之間的任何組件上完成,好比代理服務器。緩存是提高服務器性能的很棒的方法。但若是不妥善處理,會致使客戶端使用失效的結果。

緩存能夠由下面的HTTP頭控制:

這些頭部的值能夠組合起來用在Cache-Control指令中來檢查緩存結果是否有效。最通用的用於Cache-Control的指令以下:


服務決定這些頭和指令的值是根據資源的特性。

文檔化 RESTful 服務

RESTful 服務沒必要包含用於幫助客戶端發現它的文檔。由於URIs、連接、統一接口,在運行時極其容易發現 RESTful 服務。客戶端僅須要簡單地知道服務的基礎地址,而且從這個地址客戶端經過遍歷資源正在使用的連接就能發現服務。OPTION 方法能被有效地用在發現服務的處理過程當中。

這不意味着 RESTful 服務一點也不須要文檔化。沒有理由不文檔化你的服務。你應該爲開發人員和客戶端文檔化每一個資源和URI。你能夠用任何格式構建你的文檔,可是它應該包含足夠關於資源、URIs、可用方法的信息,和其餘須要訪問你的服務使用的信息。下面的 table 是個人 MyService 的簡單文檔。這個簡單短小的文檔包含了 MyService 的各方面而且足夠開發一個客戶端。

Service Name:MyService

Address: MyService/


你也能夠文檔化每一個資源的模型表示(representations )而且提供一些簡單的模型表示(representations )。

結論

開發輕量級的 Web 服務 REST 是極好的方法,容易實現,維護、暴露開放。HTTP 提供了卓越的接口來實現 RESTful 服務,好比統一接口和緩存。然而,那要開發人員正確地實現和利用這些特性。若是咱們對基礎有了正確地理解,那麼使用現有的技術好比Python、.net、java實現REST服務是很容的。我但願這篇文章爲你開始開發你本身的RESTful服務提供了足夠的信息。

參考

rest.elkstein.org/2008/

http://www.drdobbs.com/web-development/restful-web-services-a-tutorial/240169069

github.com/wanbei/blog/

文章被如下專欄收錄
6 條評論
寫下你的評論...
 
 
於洋
發現做者這篇文章和個人博文 『RESTful 架構風格概述』互補,把我那篇裏面沒有詳細闡述的內容講的更清楚,我那篇相對本文普及了更多相關知識。

blog.igevin.info/posts/
1 年前
張卓
圖1 圖2 都沒有圖片?
1 年前
炊夜冷麪
mark一下,謝謝分享
1 年前
Crzidea
推薦一個能夠自動生成RESTful API的庫,功能很是強大: github.com/Meituan-Dian
1 年前
Eric Bao
謝謝分享
1 年前
隨心泡麪
mark mark
8 個月前
推薦閱讀
相關文章
相關標籤/搜索