一、Web Services
Web Services 是一種基於組件的軟件平台,是面向服務的Internet 應用。Web Services 框架的核心技術包括SOAP ,WSDL 和UDDI ,它們都是以標准的XML 文檔的形式表示。
SOAP (“Simple Object Access Protocol”的縮寫)是Web Services 的通信協議。SOAP是一種簡單的、輕量級的基於XML 的機制,用於在網絡應用程序之間進行結構化數據交換。SOAP包括三部分:一個定義描述消息內容的框架的信封,一組表示應用程序定義的數據類型實例的編碼 規則,以及表示遠程過程調用和響應的約定。
1. 傳遞信息的格式為XML.這就使Web Services能夠在任何平台上,用任何語言進行實現。
2. 遠程對象方法調用的格式。規定了怎樣表示被調用對象以及調用的方法名稱和參數類型等。
3. 參數類型和XML格式之間的映射。這是因為,被調用的方法有時候需要傳遞一個復雜的參數,例如,一個Person對象。怎樣用XML來表示一個對象參數,也是SOAP所定義的范圍。
WSDL表示WEB服務說明語言。WSDL文件是一個XML 文檔,用於說明一組SOAP消息以及如何交換這些消息。當實現了某種服務的時候(如:股票查詢服務),為了讓別的程序調用,必須告訴大家服務接口。例如: 服務名稱,服務所在的機器名稱,監聽端口號,傳遞參數的類型,個數和順序,返回結果的類型等等。這樣別的應用程序才能調用該服務。WSDL協議就是規定了 有關Web Services描述的標准。
UDDI(“Universal Description, Discovery,and Integration”的縮寫)提供一種發布和查找服務描述的方法。UDDI 數據實體提供對定義業務和服務信息的支持。WSDL 中定義的服務描述信息是UDDI注冊中心信息的補充。
Web Services的工作原理如下:
1. Web Services 服務提供方通過WSDL描述所提供的服務,並將這一描述告知Web Services 注冊服務器。
2. 注冊服務器依據WSDL 的描述,依照UDDI的協定更新服務目錄並在Internet 上發布。
3. 用戶在使用Web Services 前先向注冊服務器發出請求,獲得Web Services 提供者的地址和服務接口信息。
4. 使用SOAP 協議與Web Services 提供者建立連接,進行通信。
二、REST(Representational State Transfer) Web Services
通常我們提到Web Services第一想法就是SOAP消息在各種傳輸協議上交互。其實SOAP最早是針對RPC的一種解決方案,簡單對象訪問協議,很輕量,但是隨着 SOAP作為Web Services的廣泛應用,不斷地增加附加的內容,使得現在開發人員覺得SOAP很重,使用門檻很高。在大並發情況下會有性能問題,在互聯網上使用不太 普及,因此並不太適合Web 2.0網站服務使用,目前大量的Web 2.0網站使用另外一種解決方案——REST。
作為SOAP模式 的替代者,REST(是“Representational State Transfer”的縮寫)是一種輕量級的Web Services架構風格,其實現和操作明顯比SOAP和XML-RPC更為簡潔,可以完全通過HTTP協議實現,還可以利用緩存Cache來提高響應速 度,性能、效率和易用性上都優於SOAP協議。
1. RESTful Web Services是什么
REST是由Roy Thomas Fielding博士在他的論文 《Architectural Styles and the Design of Network-based Software Architectures》中提出的一個術語。REST本身只是為分布式超媒體系統設計的一種架構風格,而不是標准。在RESTful系統中,服務器利用URI暴露資源,客戶端使用四個Http謂詞來訪問資源。由於客戶端接收了資源,他們被置於某種狀 態。當他們訪問一個新的資源,通常是點擊下一個連接,他們改變了,或者說是過渡了他們的狀態。為了工作,REST假設資源是能夠使用普遍的標准語法來代表的。
傳統的Web應用大都是B/S架構,它包括了如下一些規范。
1.客戶-服務器:這種規范的提出,改善了用戶接口跨多個平台的可移植性,並且通過簡化服務器組件,改善了系統的可伸縮性。最為關鍵的是通過分離用戶接口和數據存儲這兩個關注點,使得不同用戶終端享受相同數據成為了可能。
2.無狀態性: 無狀態性是在客戶-服務器約束的基礎上添加的又一層規范。它要求通信必須在本質上是無狀態的,即從客戶到服務器的每個request都必須包含理解該 request所必須的所有信息。這個規范改善了系統的可見性(無狀態性使得客戶端和服務器端不必保存對方的詳細信息,服務器只需要處理當前 request,而不必了解所有的request歷史),可靠性(無狀態性減少了服務器從局部錯誤中恢復的任務量),可伸縮性(無狀態性使得服務器端可以 很容易的釋放資源,因為服務器端不必在多個request中保存狀態)。同時,這種規范的缺點也是顯而易見得,由於不能將狀態數據保存在服務器上的共享上 下文中,因此增加了在一系列request中發送重復數據的開銷,嚴重的降低了效率。
3.緩存: 為了改善無狀態性帶來的網絡的低效性,我們添加了緩存約束。緩存約束允許隱式或顯式地標記一個response中的數據,這樣就賦予了客戶端緩存 response數據的功能,這樣就可以為以后的request共用緩存的數據,部分或全部的消除一部分交互,增加了網絡的效率。但是用於客戶端緩存了信 息,也就同時增加了客戶端與服務器數據不一致的可能,從而降低了可靠性。
B/S架構的優點是其部署非常方便,但在用戶體驗方面卻不是很理想。為了改善這種情況,我們引入了REST!
REST在原有的架構上增加了三個新規范:統一接口、分層系統和按需代碼。
1.統一接口:REST架構風格的核心特征就是強調組件之間有一個統一的接口, 這表現在REST世界里,網絡上所有的事物都被抽象為資源,而REST就是通過通用的鏈接器接口對資源進行操作。這樣設計的好處是保證系統提供的服務都是 解耦的,極大的簡化了系統,從而改善了系統的交互性和可重用性;並且REST針對Web的常見情況做了優化,使得REST接口被設計為可以高效的轉移大粒 度的超媒體數據,這也就導致了REST接口對其它的架構並不是最優的。
2.分層系統:分層系統規則的加入提高了各種層次之間的獨立性,為整個系統的復雜性設置了邊界,通過封裝遺留的服務,使新的服務器免受遺留客戶端的影響,這也就提高了系統的可伸縮性。
3.按需代碼:REST允許對客戶端功能進行擴展。比如,通過下載並執行applet或腳本形式的代碼,來擴展客戶端功能。但這在改善系統可擴展性的同時,也降低了可見性。所以它只是REST的一個可選的約束。
REST描述了一種設計Web應用的架構風格,它是一組架構約束條件和原則,滿足這些約束條件和原則的應用程序或設計就是 RESTful風格的。而符合RESTful風格的Web Services,就是我們所說的RESTful Web Services。
2. REST原則如下:
REST架構是針對Web應用而設計的,其目的是為了降低開發的復雜性,提高系統的可伸縮性。
REST中的資源所指的不是數據,而是數據和表現形式的組合, 比如“最新訪問的10位會員”和“最活躍的10位會員”在數據上可能有重疊或者完全相同,而由於它們的表現形式不同,所以被歸為不同的資源,這也就是為什 么REST的全名是Representational State Transfer的原因。資源標識符就是URI(Uniform Resource Identifier),不管是圖片,Word還是視頻文件,甚至只是一種虛擬的服務,也不管你是xml格式,txt文件格式還是其它文件格式,全部通過 URI對資源進行唯一的標識。
REST是基於HTTP協議的,任何對資源的操作行為都是通過HTTP協議來實現。以往的Web開發大多數用的都是HTTP協議中的GET和POST方法,對其他方法很少使用,這實際上是因為對HTTP協議認識片面的理解造成的。HTTP不僅僅是一個簡單的運載數據的協議,而是一個具有豐富內涵的網絡軟件的協議。它不僅僅能對互聯網資源進行唯一定位,而且還能告訴我們如何對該資源進行操作。HTTP把 對一個資源的操作限制在4個方法以內:GET,POST,PUT和DELETE,這正是對資源CRUD操作的實現。由於資源和URI是一一對應的,執行這 些操作的時候URI是沒有變化的,這和以往的Web開發有很大的區別。正由於這一點,極大的簡化了Web開發,也使得URI可以被設計成更為直觀的反映資 源的結構,這種URI的設計被稱作RESTful的URI,這為開發人員引入了一種新的思維方式:通過URL來設計系統結構。當然,這種設計方式對一些特 定情況也是不適用的,也就是說不是所有的URI都可以RESTful的。
REST之所以可以提高系統的可伸縮性,就是因為它要求所有的操作都是無狀態的。由於沒有了上下文(Context)的約束,做分布式和集群的時候就更 為簡單,也可以讓系統更為有效的利用緩沖池(Pool),並且由於服務器端不需要記錄客戶端的一系列訪問,也減輕了服務器端的性能開銷。
REST提出了如下設計准則
- 資源由URI來指定: 在Web應用中,所有的事物都應該擁有唯一的ID,代表ID的統一概念是:URI。URI構成了一個全局命名空間,使用URI標識你的關鍵資源意味着它們獲得了一個唯一、全局的ID。
- 顯式的使用HTTP方法: REST 要求開發人員顯式地使用 HTTP 方法,並且使用方式與協議定義一致。 這個基本 REST 設計原則建立了創建、讀取、更新和刪除(create, read, update, and delete,CRUD)操作與 HTTP 方法之間的一對一映射。 根據此映射:
- 若要在服務器上創建資源,應該使用 POST 方法。
- 若要檢索某個資源,應該使用 GET 方法。
- 若要更改資源狀態或對其進行更新,應該使用 PUT 方法。
- 若要刪除某個資源,應該使用 DELETE 方法。
CRUD原則:對於資源只需要四種行為:Create(創建)、Read(讀取)、 Update(更新)和Delete(刪除)就可以完成對其操作和處理
除了抽象操作為基礎的CRUD。所有的接口設計都是針對資源來設計的,也就很類似於我們的面向對象和面向過程的設計區別,只不過現在將網絡上的操作實體都作為資源來看待,同時URI的設計也是體現了對於資源的定位設計
- 資源多重表述: 針對不同的需求提供資源多重表述。這里所說的多重表述包括XML、JSON、HTML等。即服務器端需要向外部提供多種格式的資源表述,供不同的客戶端使用。比如移動應用可以使用XML或JSON和服務器端通信,而瀏覽器則能夠理解HTML。
- 無狀態: 對服務器端的請求應該是無狀態的,完整、獨立的請求不要求服務器在處理請求時檢索任何類型的應用程序上下文或狀態。無狀態約束使服務器的變化對客戶 端是不可見的,因為在兩次連續的請求中,客戶端並不依賴於同一台服務器。一個客戶端從某台服務器上收到一份包含鏈接的文檔,當它要做一些處理時,這台服務 器宕掉了,可能是硬盤壞掉而被拿去修理,可能是軟件需要升級重啟——如果這個客戶端訪問了從這台服務器接收的鏈接,它不會察覺到后台的服務器已經改變了。
REST其實並不是什么協議也不是什么標准,而是將Http協議的設計初衷作了詮釋,在 Http協議被廣泛利用的今天,越來越多的是將其作為傳輸協議,而非原先設計者所考慮的應用協議。SOAP消息完全就是將Http協議作為消息承載,以至於對於Http協議中的各種參數(例如編碼,錯誤碼等)都置之不顧。
舉個例子吧,HTTP GET 請求中的請求 URI 中的查詢字符串包括一組參數,這些參數定義服務器用於查找一組匹配資源的搜索條件。但是在許多情況下,不優雅的 Web API 使用 HTTP GET 來觸發服務器上的事務性操作——例如,向數據庫添加記錄。如:
GET /adduser?name=John HTTP/1.1
這不是非常好的設計,因為上面的 Web 方法支持通過 HTTP GET 進行狀態更改操作。Web 服務器旨在通過檢索與請求 URI 中的查詢條件匹配的資源,並在響應中返回這些資源或其表示形式,從而響應 HTTP GET 請求,而不是向數據庫添加記錄。以這種方式使用 GET 是不一致的。
REST不僅僅是一種嶄新的架構,它帶來的更是一種全新的Web開發過程中的思維方式: 通過URL來設計系統結構。在REST中,所有的URL都對應着資源,只要URL的設計是良好的,那么其呈現的系統結構也就是良好的。這點和 TDD(Test Driven Development)很相似,它是通過測試用例來設計系統的接口,每一個測試用例都表示一系列用戶的需求。開發人員不需要一開始就編寫功能,而只需要 把需要實現的功能通過測試用例的形式表現出來即可。這個和REST中通過URL設計系統結構的方式類似,我們只需要根據需求設計出合理地URL,這些 URL不一定非要鏈接到指定的頁面或者完成一些行為,只要它們能夠直觀的表現出系統的用戶接口。根據這些URL,我們就可以方便的設計系統結構。從 REST架構的概念上來看,所有能夠被抽象成資源的東西都可以被指定為一個URL,而開發人員所需要做的工作就是如何能把用戶需求抽象為資源,以及如何抽象的精確。 因為對資源抽象的越為精確,對REST的應用來說就越好,這個和傳統MVC開發模式中基於Action的思想差別就非常大。設計良好的URL,不但對於開 發人員來說可以更明確的認識系統結構,對使用者來說也方便記憶和識別資源,因為URL足夠簡單和有意義。按照以往的設計模式,很多URL后面都是一堆參 數,對於使用者來說也是很不方便的。
既然REST這么好用,那么是不是所有的Web應用都能采取此種架構呢?答案是否定的。我 們知道,直到現在為止,MVC(Model-View-Controller)模式依然是Web開發最普遍的模式,絕大多數的公司和開發人員都采取此種架 構來開發Web應用,並且其思維方式也停留於此。MVC模式由數據,視圖和控制器構成,通過事件(Event)觸發Controller來改變Model 和View。加上Webwork,Struts等開源框架的加入,MVC開發模式已經相當成熟,其思想根本就是基於Action來驅動。從開發人員角度上 來說,貿然接受一個新的架構會帶來風險,其中的不確定因素太多,並且REST新的思維方式是把所有用戶需求抽象為資源,這在實際開發中是比較難做到的,因 為並不是所有的用戶需求都能被抽象為資源,這樣也就是說不是整個系統的結構都能通過REST的來表現。所以在開發中,我們需要根據以上2點來在REST和MVC中做出選擇。我們認為比較好的辦法是混用REST和MVC, 因為這適合絕大多數的Web應用開發,開發人員只需要對比較容易能夠抽象為資源的用戶需求采取REST的開發模式,而對其它需求采取MVC開發即可。這里 需要提到的就是ROR(Ruby on Rails)框架,這是一個基於Ruby語言的越來越流行的Web開發框架,它極大的提高了Web開發的速度。更為重要的是,ROR(從1.2版本起)框 架是第一個引入REST做為核心思想的Web開發框架,它提供了對REST最好的支持,也是當今最成功的應用REST的Web開發框架。實際上,ROR的 REST實現就是REST和MVC混用,開發人員采用ROR框架,可以更快更好的構建Web應用。
三、RESTful Web Services與基於SOAP的Web Services的比較
基於SOAP的Web Services也是解決異構系統間通信問題的常用方案,那么,RESTful Web Services相對於基於SOAP 的Web Services,有什么優勢呢?或者說,我們為什么要開始學習RESTful Web Services,使用已經流行很久的基於SOAP的Web Services不就好了么?
- RESTful Web Services接口更易於使用
RESTful Web Services使用標准的 HTTP 方法 (GET/PUT/POST/DELETE) 來抽象所有 Web 系統的服務能力,而不同的是,SOAP 應用都通過定義自己個性化的接口方法來抽象 Web 服務。相對來說,RESTful Web Services接口更簡單。
RESTful Web Services使用標准的 HTTP 方法的優勢,從大的方面來講:標准化的 HTTP 操作方法,結合其他的標准化技術,如 URI,HTML,XML 等,將會極大提高系統與系統之間整合的互操作能力。尤其在 Web 應用領域,RESTful Web Services所表達的這種抽象能力更加貼近 Web 本身的工作方式,也更加自然。
- 無狀態性
HTTP 協議從本質上說是一種無狀態的協議,客戶端發出的 HTTP 請求之間可以相互隔離,不存在相互的狀態依賴。基於 HTTP 的 ROA,以非常自然的方式來實現無狀態服務請求處理邏輯。對於分布式的應用而言,任意給定的兩個服務請求 Request 1 與 Request 2, 由於它們之間並沒有相互之間的狀態依賴,就不需要對它們進行相互協作處理,其結果是:Request 1 與 Request 2 可以在任何的服務器上執行,這樣的應用很容易在服務器端支持負載平衡 (load-balance)。
- 安全操作與冪指相等特性
HTTP 的 GET、HEAD 請求本質上應該是安全的調用,即:GET、HEAD 調用不會有任何的副作用,不會造成服務器端狀態的改變。對於服務器來說,客戶端對某一 URI 做 n 次的 GET、HAED 調用,其狀態與沒有做調用是一樣的,不會發生任何的改變。
HTTP 的 PUT、DELTE 調用,具有冪指相等特性 , 即:客戶端對某一 URI 做 n 次的 PUT、DELTE 調用,其效果與做一次的調用是一樣的。HTTP 的 GET、HEAD 方法也具有冪指相等特性。
HTTP 這些標准方法在原則上保證你的分布式系統具有這些特性,以幫助構建更加健壯的分布式系統。
- RESTful Web Services更容易實現緩存
眾所周知,對於基於網絡的分布式應用,網絡傳輸是一個影響應用性能的重要因素。如何使用緩存來節省網絡傳輸帶來的開銷,這是每一個構建分布式網絡應用的開發人員必須考慮的問題。
HTTP 協議帶條件的 HTTP GET 請求 (Conditional GET) 被設計用來節省客戶端與服務器之間網絡傳輸帶來的開銷,這也給客戶端實現 Cache 機制 ( 包括在客戶端與服務器之間的任何代理 ) 提供了可能。HTTP 協議通過 HTTP HEADER 域:If-Modified-Since/Last- Modified,If-None-Match/ETag 實現帶條件的 GET 請求。
REST 的應用可以充分地挖掘 HTTP 協議對緩存支持的能力。當客戶端第一次發送 HTTP GET 請求給服務器獲得內容后,該內容可能被緩存服務器 (Cache Server) 緩存。當下一次客戶端請求同樣的資源時,緩存可以直接給出響應,而不需要請求遠程的服務器獲得。而這一切對客戶端來說都是透明的。
- 一些缺陷:
先說成熟度,SOAP發展到現在雖然已經背離了初衷,但是對於異構環境服務發布和調用,以及廠商的支持都已經達到了較為成熟的情況。不同平台,開發語言之間通過SOAP來交互的Web Services都能夠較好的互通。
反觀REST,相比於SOAP的權威性協議規范,REST實現的各種協議只能算是私有協議,當然需要遵循REST的思想,在兼容性方面會差很多。
總的來說SOAP在成熟度上優於REST。
再說效率,SOAP協議對於消息體和消息頭都有定義,同時消息頭的可擴展性為各種互聯網的標准提供了擴展的基礎。REST被人們的重視,其實很大原因是 源於其面向資源接口設計以及操作抽象簡化了開發者的不良設計,同時也最大限度的利用了HTTP最初的應用協議設計理念。
同時, REST還很好的融合Web2.0的很多前端技術來提高開發效率。例如很多大型網站開放的REST風格的API都會有多種返回形式,除了傳統的xml作為數據承載,還有JSON,RSS,等形式。
因此,相對於SOAP, REST的效率更勝一籌。
最后說安全性,SOAP在安全方面是通過使用XML-Security和XML-Signature兩個規范組成了WS-Security來實現安全控制的,當前已經得到了各個廠商的支持。 REST沒有任何規范對於安全方面作說明。
四、案例:為Web項目構建一個簡單的JSON控制器
在日常應用中,我們有大量的場合可以使用到RESTful Web Services,包括Web系統間的交互,移動客戶端與Web服務器端的通信等。只有在日常工作中更多的實踐RESTful,才能更好的理解RESTful Web Services。
無論項目使用的是哪種數據庫后端,JavaScript Object Notation (JSON) 控制器都能簡化開發工作。
假設一個PHP/MySQL 項目:建立一個 MySQL 數據庫,創建包含 HTML 的 PHP 視圖,根據需要添加 JavaScript 代碼和 CSS 文件,連接到數據庫,從數據庫提取內容來填充視圖,等等。如果您熟悉 web 開發,您一定知道分隔功能代碼的好處。例如,您知道要避免直接在視圖中輸入原始 SQL 查詢,不會在從數據庫提取數據的函數或類中混淆 HTML 標記。
但是,有時,您的項目可能擴展到您的正常 PHP/MySQL 舒適水平之外。例如,您可能不僅擁有需要來自一個數據庫的數據的常規 web 視圖,還擁有外部應用程序(比如 Facebook),甚至還擁有訪問相同數據的移動設備(比如智能手機)。
您可能會發現自己身陷這樣一種情況:數據庫更改,或者要求您處理某種類型的 XML 存儲庫。在這些情況下,您對 MySQL 的盲目依賴可能會阻礙您完成項目的工作。
此時可以考慮將一個 RESTful JSON 控制器放置到項目中,將它用作一個虛擬交通警察,負責發送請求並接收來自您的數據源的響應。下面將並展示一種建立控制器的方法。其結果是從一個數據源檢索數據的簡單方法,檢索的數據采用標准化的格式,可以使用 PHP 或 JavaScript 代碼輕松解析。
- 在一個典型的 REST 架構中,一個客戶機發送一個請求到服務器,服務器使用請求資源的一個表示來進行響應。資源可以是任何信息對象,比如數據庫或文檔,它的表示通常是一個格式化的文檔(通常是 XML 或 JSON),充當它的當前或被請求狀態的一個快照。
- REST 資源通常使用有意義的 URLs 標識,這些 URLs 接受不同的請求動詞 GET、POST、PUT 和 DELETE。這些動詞有點類似於許多開發人員都熟悉的 create-retrieve-update-delete (CRUD) 模型。
- 例如,如果您想檢索數據,則使用 GET 請求;要創建數據,則使用 POST 請求;要更新數據,則使用 PUT 請求;最后,要刪除數據,則使用 DELETE 請求。
- 另一個需要考慮的重要因素是響應。RESTful 服務通常在它的響應中提供兩個有意義的組件:響應主體本身和一個狀態碼。許多 REST 服務實際上允許用戶指定一個響應格式(比如 XML、CSV、序列化的 PHP 對象或純文本),方法有兩種:一是發送一個 ACCEPT 參數;二是指定一個文件擴展名(例如,/api/users.xml 或 /api/users.json)。其他 REST 服務器,比如您將在這里實現的服務器,擁有硬編碼的響應格式。這些格式同樣可以接受,只要它們已經有文檔記載。
- 響應代碼往往是 HTTP 狀態碼。這種模式的優點是可以使用知名的現有狀態碼來標識錯誤或成功。狀態碼 201(CREATED)是一個成功 POST 請求的完美響應。錯誤碼 500 表明在您所處的這端(服務端)上發生了錯誤,但錯誤碼 400 表明客戶端上出現了失敗(BAD REQUEST)。如果服務器出現故障,將發送錯誤碼 503(SERVICE UNAVAILABLE)。
一個應用程序擁有的一個數據源包含一些用戶信息,名、姓、郵件地址、以及Twitter 帳戶。如果您正在設置一個典型的 PHP 應用程序,您需要創建一個 mysql_query() 包裝器來使用一個 SQL 查詢從數據庫提取一個清單。您還需要編寫一些 PHP 代碼,用於調用那個函數並循環結果集,以便在應用程序視圖中顯示數據。
設置一個簡單的 REST 控制器,該控制器允許一個針對 /users/list 的、不帶任何參數的 GET 請求,然后調用適當的數據庫函數並返回一個 JSON 格式的清單。接下來,您的應用程序可以解碼那個 JSON 數據,以任何必要的方式循環該數據,以便顯示數據內容。
另外,您可以通過測試檢查是否有任何參數被發送到 /users/list。例如,如果您發送一個 GET 請求到 /users/list/1,那么響應將只包含 ID 為 1 的用戶的細節。除 JSON 格式外,您甚至可以允許其他格式,比如 XML、CSV 和的 PHP 對象。
一個 RESTful JSON 控制器對於您的開發工作的作用並非僅僅是在視圖和數據源之間放置一個額外的功能層。想想看,您的基本 PHP 視圖也許不是請求信息的惟一組件。例如,您可能會使用 jQuery 通過一個 Ajax 接口請求數據,或者,您的用戶可能會通過一部智能手機或一個 Facebook 應用程序請求數據。
在這些情況下,一個接收請求並以一種容易理解(和預測)的格式提供響應的 RESTful 接口可能會極大地簡化您的開發工作。作為負責 PHP 視圖(或者甚至 iPhone 應用程序)的開發人員,您可以發送一些請求到一個 URL 並接收一組預期響應。在 JSON 控制器的另一面,應用程序可以被鈎掛(hook)到 MySQL、PostgreSQL、一個 XML 文件存儲庫、或者什么也不掛。
1. 首先創建一個簡單的事件數據庫架構(MYSQL)
CREATE TABLE `events` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARYKEY , `title` VARCHAR( 255 ) NOT NULL , `address` VARCHAR( 255 ) NOT NULL , `start_time` DATETIME NOT NULL , `description` TEXT NOT NULL );
2. 創建一個典型 PHP 模型文件,它連接到這個數據庫並使用一個 SQL 查詢來識別事件。
$SERVER = 'name'; $USER = 'username'; $PASS = 'pw'; $DATABASE = 'dbname'; if (!($mylink = mysql_connect($SERVER, $USER, $PASS))) { echo "Sorry, could not connect to DB. Contact your sysadmin for help!"; exit; } mysql_select_db( $DATABASE ); class Events{ function get_events($day){ $ret_array = array(); $sql ="select id,title,address,start_time,description from events where start_time like '$day%' order by start_time asc"; $result = mysql_query($sql); while($data = mysql_fetch_object($result)){ $obj['id'] = $data->id; $obj['title'] = $data->title; $obj['address'] = $data->address; $obj['start_time'] = $data->start_time; $obj['description'] = $data->description; $ret_array[] = $obj; } return $ret_array; } }
對這個函數的一個簡單調用時,您將得到如下所示的結果。
$EVENT = new Events; $today = '2010-06-17'; $events = $EVENT->get_events($today); print_r($events); /* results in Array ([0] => Array( [id] => 2 [title] => Event #2 [address] => 156 My Avenue, MyTown, USA 78727 [start_time] => 2010-06-17 11:30:00 [description] => Join us for lunch to hear FABULOUS SPEAKER. ) [1] => Array( [id] => 1 [title] => Event #1 [address] => 123 My Street, Anytown USA 78727 [start_time] => 2010-06-17 15:30:00 [description] => A great event! Hope to see you there! ) ) */
通過 json_encode() 運行相同的代碼,將得到一個可移植的 JSON 對象(如 所示)
[ {"id":"2", "title":"Event #2", "address":"156 My Avenue, MyTown, USA 78727", "start_time":"2010-06-17 11:30:00", "description":"Join us for lunch to hear FABULOUS SPEAKER. " }, {"id":"1", "title":"Event #1", "address":"123 My Street, Anytown USA 78727", "start_time":"2010-06-17 15:30:00", "description":"A great event! Hope to see you there!" } ]
目標是構建這樣一個簡單的控制器:它知道應該運行哪個模型和函數,然后返回一個 JSON 對象作為響應,這個響應可用於事務的遠端。這個控制器非常簡單,看起來如下所示。將如下所有代碼粘貼到一個名為 json.php 的文件中。
class JSON{ var $response = ''; function JSON($model,$function,$params){ $REQUEST = new $model; $data = $REQUEST->$function($params); $this->response = json_encode($data); } }
調用的模型,實例化 JSON 類,然后傳入 3 個參數:模型的類名、要運行的函數、以及該函數的參數。這個類然后調用那個函數並獲取一個響應,該響應通過 json_encode() 運行。
3. 最后一步是創建包含對 JSON 數據的請求的文件。這個特殊的文件(您可以稱之為 listing.php)可以設置為接收 3 個 GET 變量(模型、函數和參數各一個),然后將這些變量傳遞給 JSON 類(如清單 7 所示)
請求代碼
//this is the code that contains the model require 'events.php'; //this is the JSON controller require 'json.php'; //pass in your three GET parameters $MODEL = $_GET['model']; $FUNCTION = $_GET['function']; //check to see if param is passed in //if not, use today's date in this instance if (isset($_GET['param'])){ $PARAM = $_GET['param']; }else{ $PARAM = date("Y-m-d"); } //invoke $JSON = new JSON($MODEL,$FUNCTION,$PARAM); //access the response variable echo $JSON->response;
可以將這個文件加載到一個瀏覽器中,並獲取一個 JSON 對象。再通過 json_decode() 將這個 JSON 對象發送回去,使用 JavaScript 代碼處理它,或者讓它保持原樣。
整個這個流程的一個甚至更好的方法是創建一個更緊密模擬 RESTful 服務器的路徑結構。例如,可以創建一個名為 events/today 的目錄結構,該結構包含一個名為 index.php 的文件。通過將您的瀏覽器指向 /events/today,無需傳入任何 GET 變量,您就可以基於如下的代碼取回一個 JSON feed。
/events/today/index.php 中的代碼
require '../../events.php'; require '../../json.php'; $MODEL ="Events"; $FUNCTION ="get_events"; $PARAM = date("Y-m-d"); //invoke $JSON =new JSON($MODEL,$FUNCTION,$PARAM); echo $JSON->response; //prints out [ {"id":"3", "title":"Test Event 3", "address":"111 Main Street, Austin TX 78727", "start_time":"2010-06-10 15:15:00", "description":"Testing 456." } ]
使用這種方法,您可以為您的視圖和支持的應用程序簡化一些數據提取要求。開發人員無需記住底層數據庫的所有細節,相反,他們可以輕松命中 URLs 並接收他們尋找的響應來繼續他們的工作。
參考:
- http://tech.it168.com/a2012/0919/1400/000001400252.shtml
- http://express.ruanko.com/ruanko-express_37/technologyexchange6.html
- http://nepoulia.blog.51cto.com/2722590/579151
- 10 個技巧讓你的 RESTful Web 服務更加實用
- 為您的Web項目構建一個簡單的JSON控制器
- 在CodeIgniter框架中使用RESTful服務
- 淺談REST
