當HTTP被髮明出來的時候,其實REST就已經存在了。惋惜這麼多年來,WEB開發模式卻愈來愈背離HTTP的本質,捨本逐末的追求起RPC之類的東西。此時REST從新回到人們的視線裏,無疑讓你們開始反思過去走過的彎路。php
本文並不想從頭介紹REST,只是想舉例說明一下須要注意的問題:數據庫
先來看看人們對REST的困惑:瀏覽器
REST什麼樣子?
最通常的REST例子,相似下面的樣子:安全
2 |
DELETE /articles/123 刪除 |
3 |
PUT /articles/123 更新或建立 |
順便說說幾個知識點:服務器
GET操做是安全的。所謂安全是指無論進行多少次操做,資源的狀態都不會改變。好比我用GET瀏覽文章,無論瀏覽多少次,那篇文章還在那,沒有 變化。固然,你可能說每瀏覽一次文章,文章的瀏覽數就加一,這不也改變了資源的狀態麼?這並不矛盾,由於這個改變不是GET操做引發的,而是用戶本身設定 的服務端邏輯形成的。架構
PUT,DELETE操做是冪等的。所謂冪等是指無論進行多少次操做,結果都同樣。好比我用PUT修改一篇文章,而後在作一樣的操做,每次操做後的結果並無不一樣,DELETE也是同樣。順便說一句,由於GET操做是安全的,因此它天然也是冪等的。ui
POST操做既不是安全的,也不是冪等的,好比常見的POST重複加載問題:當咱們屢次發出一樣的POST請求後,其結果是建立出了若干的資源。this
安全和冪等的意義在於:當操做沒有達到預期的目標時,咱們能夠不停的重試,而不會對資源產生反作用。從這個意義上說,POST操做每每是有害的,但不少時候咱們仍是不得不使用它。spa
還有一點須要注意的就是,建立操做可使用POST,也可使用PUT,區別在於POST是做用在一個集合資源之上的(/articles), 而PUT操做是做用在一個具體資源之上的(/articles/123),再通俗點說,若是URL能夠在客戶端肯定,那麼就使用PUT,若是是在服務端確 定,那麼就使用POST,好比說不少資源使用數據庫自增主鍵做爲標識信息,而建立的資源的標識信息究竟是什麼只能由服務端提供,這個時候就必須使用 POST。設計
瀏覽器不支持PUT/DELETE方法怎麼辦?
大部分瀏覽器只支持GET/POST方法,這使得咱們沒法完美的實現REST。對於這樣的狀況,大體有幾種解決方法,一種是在表單里加入一個 _method之類名字的隱藏字段,用於表示真正的方法,另外一種是使用X-HTTP-METHOD-OVERRIDE頭信息來重載POST。
HTTP方法夠用麼?
從上面的例子,咱們能夠看到,經過使用已有的HTTP方法:POST,DELETE,PUT,GET就能夠完成資源的增刪改查,但在實際狀況 中,咱們須要作的操做每每並不只僅侷限在簡單的增刪改查操做中,好比說咱們要把一篇文章「置頂」,可是HTTP方法裏沒有一個和「置頂」操做相對應的方 法,這時候該怎麼辦呢?REST對相似問題的解決方案是:建立一個新的資源!在上面的例子裏,咱們能夠這樣:
經過建立出一個新的資源(toparticles),咱們就可使用簡單的HTTP方法通吃一切操做了。
REST反對使用Session麼?
牢記一點,REST拒絕Session!這是由於REST強調無狀態性。這裏的狀態指的的應用狀態,也能夠稱之爲會話狀態。一旦在服務端保持了這樣的狀態,那麼架構的可擴展性將大打折扣。在REST看來,任何相似的狀態自己都應該是一個獨立的資源。
Cookie對REST有害麼?
一分爲二的看,若是Cookie裏保存的是應用狀態的話,就沒有問題。由於應用狀態原本就屬於客戶端。但若是使用Cookie保存相似PHPSESSIONID之類的東西就不對了,由於這樣的數據並不屬於客戶端狀態,它只不過是使用Session的藉口而已。
再來看看REST在PHP中的現狀:
PHP裏的REST實現案例很少,有點影響都就是CakePHP和Zend,下面分別看看他們的實現:
CakePHP:
設定路由:
1 |
Router::parseExtensions( 'xml' ); |
2 |
Router::mapResources( 'articles' ); |
編寫控制器:
1 |
class ArticlesController extends AppController { |
2 |
var $components = array ( 'RequestHandler' ); |
3 |
function view( $id = null) { |
4 |
$article = $this ->Article->findById( $id ); |
5 |
$this ->set(compact( 'article' )); |
視圖:
2 |
<?php echo $xml ->serialize( $article ); ?> |
差很少就這樣了,相應的,還能夠實現其餘的功能,因而,以下REST操做便成爲可能:
2 |
DELETE /articles/123.xml |
整體看,CakePHP的REST實現基本上是按Rails風格來實現的,大致還過得去。
ZendFramework:
ZendFramework經過Zend_Rest組件來實現Rest功能:
服務端:
1 |
require_once 'Zend/Rest/Server.php' ; |
2 |
function sayHello( $who , $when ) |
4 |
return "Hello $who, Good $when" ; |
6 |
$server = new Zend_Rest_Server(); |
7 |
$server ->addFunction( 'sayHello' ); |
客戶端:
1 |
require_once 'Zend/Rest/Client.php' ; |
3 |
$client ->sayHello( 'Davey' , 'Day' ); |
這時候,咱們看一下Web服務器的日誌,會發現生成了一條以下的記錄:
1 |
GET /path/to/servier/script?method=sayHello&arg0=Davey&arg1=Day&rest=1 HTTP/1.1 |
咱們發現,實際操做方法是由URL中的method=sayHello指定的,而HTTP固有方法(GET/POST等)則成爲了擺設,這是典 型的RPC風格,若是你們對比Zend_Rest和Zend_XmlRpc文檔的話,會明顯發現它們根本就是一個東西,因此說,Zend_Rest是一個 REST僞實現。
這個基本 REST 設計原則創建了建立、讀取、更新和刪除(create, read, update, and delete,CRUD)操做與 HTTP 方法之間的一對一映射。 根據此映射: 1)若要在服務器上建立資源,應該使用 POST 方法。 2)若要檢索某個資源,應該使用 GET 方法。 3)若要更改資源狀態或對其進行更新,應該使用 PUT 方法。 4)若要刪除某個資源,應該使用 DELETE 方法。