以前就是覺得 /nowamagic/article/article_id 這樣的地址非常的漂亮,但是那只是表象罷了,了解深入以后,發現必須有一個客戶端的Ajax Engine和Server端的服務配合,才能實現一個REST風格的應用,下面就是我的實驗。
要對外提供哪些服務。服務器端的服務可能會被眾多的瀏覽器請求,也可能被第三方應用程序所調用,所以需要從總體上來考慮這個對外的“應用程序接口”(API),盡量保持接口的穩定性。REST是一種風格,並且形成了自己的規則,構建這樣的應用,應盡量遵循REST的原則。
以一個足球服務為例,眾多的觀眾會要求觀看比賽的記錄,上傳新比賽記錄,更新比賽記錄,更正現有的比賽或者刪除比賽等等。像這樣描述的話,我們需要提供眾多不同的服務,並且最終會倒在維護一致性的工作上。那么應該怎么做呢,考慮一下客戶可能的請求方式:
GET方式請求一個新建比賽服務:
http://example.com/newMatch?id=995&bluebaggers=150&redlegs=60
POST或PUT方式請求一個新建比賽服務:
http://example.com/newMatch
附加的XML為:
1 |
< match id = "995" > |
2 |
< score team = "bluebaggers" >150</ score > |
3 |
< score team = "redlegs" >60</ score > |
4 |
</ match > |
CGI風格的POST或PUT請求:
http://example.com/newMatch
請求體:
id=995&bluebaggers=150&redlegs=60
或者一個維護服務的GET請求:
http://example.com/matchMaintenance/command=newMatch&id=995&bluebaggers=150&redlegs=60
或者POST請求
http://example.com/matchMaintenance/command=newMatch
1 |
< match id = "995" > |
2 |
< score team = "bluebaggers" >150</ score > |
3 |
< score team = "redlegs" >60</ score > |
4 |
</ match > |
以此類推,可以有很多這樣的功能。有些人覺得這並不是什么問題,對越來越多的請求,我們只要建立服務,然后給出相應的說明就可以了。但是,他還是存在缺點的。
也許我們會假設訪問只是來自腳本,那么這種情況可能會簡單一點。但實際上,還有很多的因素會涉及到,例如網頁瀏覽器(會存在后撤和刷新按鈕的問題)、Web服務器(可能會有緩存和編譯問題)、網絡路由和緩存問題、應對爬蟲的騷擾、一些個人站點對網站內容的抓取。如果我們考慮這些不同的請求,我們的程序就可以表現的更健壯。
理想的情況下,一個服務應該有自我說明的能力。如果一個服務建立在一種約定俗成的條件下,那么大家就很容易適應並且進行后續的開發。
REST就是考慮了這些因素,可以使用RESTful API來實現上面的服務。
RESTful 原則介紹
REST的主要原則有:
用URL表示資源。資源就像商業實體一樣,是我們希望作為API實體呈現的一部分。通常是一個名詞,每個資源都用一個獨一無二的URL來表示。
HTTP方法表示操作。REST充分利用了HTTP的方法,特別是GET、POST、PUT和DELETE。注意XMLHttpRequest對象實現了全部的方法,具體可以參看W3C HTTP 1.1 Specification。
也就是說,客戶端的任何請求都包含一個URL和一個HTTP方法。回到上面的例子中,比賽顯然是一個實體,那么對於一個特定比賽的請求就表示為:
http://example.com/matches/995
這種方式是清晰明了的,也許和精確命名的方式有所區別,但是只要遵循這種形式,我們就能很快的進行GET、DELETE、UPDATE和新建操作。
RESTful的原則:
- URL表示資源
- HTTP方法表示操作
- GET只是用來請求操作,GET操作永遠都不應該修改服務器的狀態。但是這個也要具體情況進行分析,例如一個頁面中的計數器,每次訪問的時候確實引起了服務器數據的改變,但是在商業上來說,這並不是一個很重要的改變,所以仍然可以接收使用GET的方式來修改數據。
- 服務應該是無狀態的
在有狀態的會話中,服務器可以記錄之前的信息。而RESTful風格中是不應該讓服務器記錄狀態的,只有這樣服務器才具備可擴展性。當然,我們可以在客戶端使用cookie,而且只能用在客戶端向服務器發送請求的時候。
- 服務應當是“冪等”的
“冪等”表示可以發送消息給服務,然后可以再次毫不費力的發送同樣的消息給服務。例如,發送一個“刪除第995場比賽”的消息,可以發送一次,也可以連續發送十次,最后的結果都會保持一致。當然,RESTful的GET請求通常是冪等的,因為基本上不會改變服務器的狀態。注意:POST請求不能被定義為“冪等”,特別是在創建新資源的時候,一次請求創建一個資源,多次請求會創建多個資源。
- 擁抱超鏈接
- 服務應當自我說明
例如 http://example.com/match/995 請求了一個具體的比賽,但是 http://example.com/match 並沒有對任何實體進行請求,因此,應當返回一些介紹信息。
- 服務約束數據格式。數據必須符合要求的格式
在PHP的程序中,想要實現這種REST風格的URL,僅僅依靠程序是不行的,還需要在服務器端配置rewrite規則,例如,對於一個REST風格的資源請求:
http://www.api.com/product/113
一般實現的腳本為
http://www.api.com/product.php?id=113
這個是基於QueryString的,也可以做一個統一的 index.php 入口,然后通過處理URI的方式實現,例如:
http://www.api.com/index.php/product/113
這樣的URL,都可以通過rewrite來實現rest風格。總之,REST是一種程序設計的風格,為我們整理自己的應用設計提供了一個原則,在利用這些原則帶來的遍歷的同時,可以根據實際情況進行靈活的處理。