來源:LAMP兄弟連 作者:LAMP兄弟連
REST(Representational State Transfer表述性狀態轉移)是一種體系架構,它爲客戶端和服務器之間的數據交互提供了指導。它將客戶/服務器通信這種計算模型抽象到了Web層面。
REST最早是在Roy Thomas Fielding博士的博士論文中提出的,REST是一種針對網絡應用的設計和開發方式,是一種風格,可以降低開發的複雜性,提高系統的可伸縮性。
REST強調如下的體系架構概念。
1、網絡上的所有事物都被抽象爲資源(resource);
2、每個資源對應一個唯一的資源標識(resource identifier);
3、通過通用的連接器接口(generic connector interface)對資源進行操作;
4、對資源的各種操作不會改變資源標識;
5、所有的操作都是無狀態的(stateless)。
REST對於信息的核心抽象是資源,一個資源是一組實體的概念上的映射,而REST使用一個資源標識符來標識組件之間交互所涉及到的特定資源。REST連接器提供了訪問和操作資源的值集合的一個通用接口。在這裏所有的操作中,它們都是無狀態的,這樣就不必在多個請求之間保存狀態,不必考慮上下文的約束,從而允許服務器組件迅速釋放資源,並進一步簡化其實現,從而提高系統的可伸縮性。
現在我們就一個簡單的示例演示下REST。
在我們的示例中以java script爲客戶端,與HTTP服務器體系架構配合工作,使用URL作爲資源標識,並將HTTP作爲連接器接口。
客戶端的代碼:
001 |
function
rest() { |
002 |
|
003 |
var XMLHttpFactories = [ |
004 |
|
005 |
function () { return new
XMLHttpRequest()}, |
006 |
|
007 |
function () { return new
ActiveXObject( "Msxml2.XMLHTTP" )}, |
008 |
|
009 |
function () { return new
ActiveXObject( "Msxml3.XMLHTTP" )}, |
010 |
|
011 |
function () { return new
ActiveXObject( "Microsoft.XMLHTTP" )} |
012 |
|
013 |
];
|
014 |
|
015 |
|
016 |
|
017 |
var xmlhttp = false; |
018 |
|
019 |
for ( var i = 0; i < XMLHttpFactories.length; i++) {
|
020 |
|
021 |
try { |
022 |
|
023 |
xmlhttp = XMLHttpFactories[i](); |
024 |
|
025 |
} catch (e) { |
026 |
|
027 |
continue ; |
028 |
|
029 |
} |
030 |
|
031 |
break ; |
032 |
|
033 |
} |
034 |
|
035 |
// 建立XMLHttpRequest對象 |
036 |
|
037 |
this.xmlhttp = xmlhttp; |
038 |
|
039 |
}
|
040 |
|
041 |
rest.prototype._get = function (url, data) { |
042 |
|
043 |
var xmlhttp = this.xmlhttp; |
044 |
|
045 |
xmlhttp.open ( 'GET' , url + "&" + data, false); |
046 |
|
047 |
xmlhttp.send (null); |
048 |
|
049 |
return xmlhttp.responseText; |
050 |
|
051 |
}; |
052 |
|
053 |
|
054 |
|
055 |
rest.prototype._post = function (url, data) { |
056 |
|
057 |
var xmlhttp = this.xmlhttp; |
058 |
|
059 |
xmlhttp.open ( 'POST' , url, false); |
060 |
|
061 |
xmlhttp.setRequestHeader( "Content-Type" , "application/x-www-form-urlencoded; charset=UTF-8" ); |
062 |
|
063 |
xmlhttp.setRequestHeader ( "Content-Length" , data.length); |
064 |
|
065 |
xmlhttp.send (data); |
066 |
|
067 |
return xmlhttp.responseText; |
068 |
|
069 |
}; |
070 |
|
071 |
|
072 |
|
073 |
rest.prototype.get = function (url, data) { |
074 |
|
075 |
url = url += "?op=GET" ; |
076 |
|
077 |
return this._get(url, data); |
078 |
|
079 |
} |
080 |
|
081 |
|
082 |
|
083 |
rest.prototype.post = function (url, data) { |
084 |
|
085 |
url = url += "?op=POST" ; |
086 |
|
087 |
return this._post(url, data); |
088 |
|
089 |
} |
090 |
|
091 |
|
092 |
|
093 |
rest.prototype.put = function (url, data) { |
094 |
|
095 |
url = url += "?op=PUT" ; |
096 |
|
097 |
return this._post(url, data); |
098 |
|
099 |
}; |
100 |
|
101 |
|
102 |
|
103 |
rest.prototype.del = function (url, data) { |
104 |
|
105 |
url = url += "?op=DELETE" ; |
106 |
|
107 |
return this._get(url, data); |
108 |
|
109 |
}; |
110 |
|
111 |
|
112 |
|
113 |
function
t() { |
114 |
|
115 |
var restobj = new
rest(); |
116 |
|
117 |
document.write (restobj.get( "http://localhost/test/service.php" , "content=GET
Content" )); |
118 |
|
119 |
document.write (restobj.post( "http://localhost/test/service.php" , "content=POST
Content" )); |
120 |
|
121 |
document.write (restobj.put( "http://localhost/test/service.php" , "content=PUT
Content" )); |
122 |
|
123 |
document.write (restobj.del( "http://localhost/test/service.php" , "content=DELETE
Content" )); |
124 |
|
125 |
} |
126 |
|
127 |
t(); |
128 |
|
129 |
如上所示,我們在客戶端創建XMLHttpRequest對象,並且通過這個對象實現通過HTTP對服務器的操作GET、PUT、POST和 DELETE 以檢索和修改資源。HTTP則把對每一個資源的操作都限制在了4個之內:GET、POST、PUT和 DELETE 。HTTP的這四個方法分別對應我們常見的CRUD操作,具體對應關係如下: |
130 |
|
131 |
C(Create) <==> POST
|
132 |
|
133 |
R(Read/Retrieve) <==> GET |
134 |
|
135 |
U(Update) <==> PUT
|
136 |
|
137 |
D( Delete /Destroy) <==> DELETE |
雖然HTTP提供了這4個方法,但是在某些情況下,PUT和DELETE方法是不可用的,於是我們在這裏使用GET方法和POST方法進行替代。另外,在JS操作時,需要注意同源策略(Same Origin Policy,SOP),考慮跨域的問題。
服務端代碼:
01 |
<?php |
02 |
|
03 |
/** |
04 |
|
05 |
* REST後臺程序簡單示例 |
06 |
|
07 |
*/ |
08 |
|
09 |
class
Resource { |
10 |
|
11 |
public function get( $request ) { |
12 |
|
13 |
echo 'content=' , $request [ 'content' ], ";
get resource Successful<br />" ; |
14 |
|
15 |
}
|
16 |
|
17 |
|
18 |
|
19 |
public function post( $request ) { |
20 |
|
21 |
echo 'content=' , $request [ 'content' ], ";
post resource Successful<br />" ; |
22 |
|
23 |
}
|
24 |
|
25 |
|
26 |
|
27 |
public function put( $request ) { |
28 |
|
29 |
echo 'content=' , $request [ 'content' ], ";
update resource Successful<br />" ; |
30 |
|
31 |
}
|
32 |
|
33 |
|
34 |
|
35 |
public function delete ( $request )
{ |
36 |
|
37 |
echo 'content=' , $request [ 'content' ], ";
delete resource Successful<br />" ; |
38 |
|
39 |
}
|
40 |
|
41 |
} |
42 |
|
43 |
$request
= $_REQUEST ;
|
44 |
|
45 |
$op
= $request [ 'op' ]; |
46 |
|
47 |
$op
= strtolower ( $op ); |
48 |
|
49 |
$ops
= array ( |
50 |
|
51 |
'get' => 1, |
52 |
|
53 |
'post' => 1, |
54 |
|
55 |
'put' => 1, |
56 |
|
57 |
'delete' => 1, |
58 |
|
59 |
); |
60 |
|
61 |
if (!isset( $ops [ $op ])) { |
62 |
|
63 |
die ( 'input error!' ); |
64 |
|
65 |
} |
66 |
|
67 |
$resource
= new Resource(); |
68 |
|
69 |
$resource -> $op ( $request ); |
70 |
|
71 |
?> |
如上所示,是我們提供REST數據的服務器端的代碼。這裏只是簡單的應答請求,輸出標識內容。
以上就是我們這個示例的全部了,在這個示例中,我們的整體架構是基於最簡單的客戶端/服務器模式,客戶端使用java script,以Ajax實現。我們不需要使用PHP之類的語言生成客戶端的頁面,所有的客戶端的工作都交給java script去做,包括從服務器端讀取數據,生成頁面內容,頁面佈局等等。在服務器端,我們需要做的是提供資源,針對客戶端的請求返回對應的資源,此時的服務器是無狀態的。客戶與服務器之間的數據交換不依賴於服務器,由客戶端來維護狀態。