1. 程式人生 > >REST與RESTFul API最佳實踐

REST與RESTFul API最佳實踐

我經常會面試一些做PHP的開發者,讓我很奇怪的是,10個人總有8個多不知道什麼是REST服務,甚至是沒有聽說過。但RESTFul API已經是現在互聯網裡對外開放介面的主流模式,可參考:

數一數年限,據我接觸REST到現在也差不多有8年左右了。可能大家現在對從JavaScript客戶端直接訪問伺服器API這種模式非常的習以為常,但在8年前,Web並不是現在這個樣子的。要說REST,我們先來看看在REST流行之前Web客戶端是如何訪問伺服器介面的。

早期在移動端沒有流行之前,Web API的概念還非常的弱,當時是網站盛行的年代,基本遵循著後臺-前端的模型。後臺產生資料,然後通過“模板”的形式將資料繫結到前端HTML程式碼裡(渲染)。如下圖所示:

圖片描述

那麼這裡就有一個“域”的概念,JavaScript只能訪問同一個域的伺服器。比如我們將一個站點部署在A這個域名www.a.com下,那麼這個站點的前端JavaScript只能訪問域名為www.a.com的服務端。如果我們需要訪問非A站點的其他“服務”怎麼辦?看看下圖:

圖片描述

在當時通用的做法是使用SOAP,Simple Object Access Protocol,簡單物件協議,它使用XML作為資料的描述。我們看看使用SOAP的解決方案:

圖片描述

JavaScript是不能直接訪問SOAP服務的,需要首先訪問自己的網站後臺,再有網站後臺訪問SOAP服務。而且不同語言的網站後臺,方位SOAP服務都需要有首先生成自己特定語言的“代理類”,Java有Java的、C#有C#的,這相當的繁瑣與不好理解。這個時候我們的思考點來了,網站的後臺對我來說意義是什麼? 我為什麼不能直接訪問服務?為什麼我不能把網站裡的業務程式碼也提取成服務,最後變成以下的理想情況:

圖片描述

網站的後臺幾乎是個“殼子”,只負責網站本身的HTML頁面、CSS、JavaScript檔案等靜態頁面。而業務邏輯,交給服務來提供就好了。這樣做的最大的好處是,業務變得獨立了,可以被多個“網站”來共享訪問了。有沒有覺得挺熟悉?這個模式就是現在VUE、AngularJS等框架做的單頁面應用程式。但是,在當時這種模式並不流行。我在很多年前就嘗試這樣的思維來構建Web,但是由於沒有現在VUE、AngularJS等強大的SPA框架支援,效果並不好。但,我相信這種簡潔的模式是Web的未來。我一向崇尚簡潔,當年丟掉Flex、Silverlight、ASP.Net WebForm,獨獨選擇JavaScript就是因為其他幾個封裝太多。

很多人認為模板引擎就是很好的前後端分離,可我不這麼認為,SPA才是真正的前後端分離,他們之間使用AJax通訊,前端就是最簡單的HTML,前端開發人員一行伺服器程式碼都看不到,這才是真的和語言無關,才是真正的前後端分離。

我來分析下,為什麼以前SPA應用並不流行。
第一,一個是網站的思維根深蒂固;
第二,就是出於效能考慮,單頁面頻繁的Ajax請求將給伺服器造成巨大的壓力。而網站網頁的靜態化技術已經是非常的成熟的了,所以SPA這個概念在早期並不怎麼提倡。而且SPA也有自己的侷限性,並不是所有的網站都適合用SPA來代替。但現在伺服器快取技術的發展(特別是Memcache和Redis出現後)大大的解決了伺服器支援SPA負載過高的問題,甚至比傳統的網頁靜態化技術更加的簡單易用;再加上VUE、AngularJS強大的能力,這才使SPA真正的流行起來。
第三,前端要跨域訪問伺服器在當時並不是那麼容易,沒有一個標準的規範來定義跨域,各種旁門左道的跨域都不是那麼的好用。

那麼我個人認為有兩個標緻性的事物重新整理了人們對於API和服務的理解:一個是移動端的流行,第二個就是REST理念的流行。
移動端我們就不談了。我們來談談REST。我個人認為REST並不是什麼技術,而是由於它的流行,讓人們逐漸的接受了服務即資源,擴充套件和打破了開發者對Web的理解。

沒有REST的時候,客戶端可不可以直接跨域訪問服務?可以。但並沒有一個標準來引導開發者如何設計出適合服務的API介面。REST的流行,替代了SOAP(某些領域裡SOAP還是有一席之地),它足夠簡單、輕量、語義明確,非常適合移動端盛行的這個年代。

REST:REpresentational State Transfer,中譯為“表屬性狀態傳遞”。這是什麼鬼?這並不重要,本來就個名字就源自於國外的一個博士的一篇論文。我們主要要知道基於這篇論文裡的理論,衍生出了RESTFul API的介面設計風格。
我們一起來看看RESTFul API有哪些特點:

基於“資源”,資料也好、服務也好,在RESTFul設計裡一切都是資源。
無狀態。一次呼叫一般就會返回結果,不存在類似於“開啟連線-訪問資料-關閉連線”這種依賴於上一次呼叫的情況。
URL中通常不出現動詞,只有名詞
URL語義清晰、明確
使用HTTP的GET、POST、DELETE、PUT來表示對於資源的增刪改查
使用JSON不使用XML

我舉個例子:
網站:/get_user?id=3
RESTFul: GET /user/3 (GET是HTTP型別)

有些同學可能會說,GET、POST我也經常用啊。但是在網站裡的GET和POST同RESTFul中的GET、POST是不一樣的。網站裡使用GET、POST的選擇點在於,簡單的用GET、複雜物件用POST;但在REST裡,GET對應的是查詢一個資源,而POST對應的是新增一個資源,意義是決然不同的。理解這一點非常重要。

好,我們接著來看一看RESTFul API的一些最佳實踐原則:

使用HTTP動詞表示增刪改查資源, GET:查詢,POST:新增,PUT:更新,DELETE:刪除
返回結果必須使用JSON
HTTP狀態碼,在REST中都有特定的意義:200,201,202,204,400,401,403,500。比如401表示使用者身份認證失敗,403表示你驗證身份通過了,但這個資源你不能操作。
如果出現錯誤,返回一個錯誤碼。比如我通常是這麼定義的:
圖片描述

API必須有版本的概念,v1,v2,v3
使用Token令牌來做使用者身份的校驗與許可權分級,而不是Cookie。
url中大小寫不敏感,不要出現大寫字母
使用 - 而不是使用 _ 做URL路徑中字串連線。
有一份漂亮的文件~(很重要)
以上只是列出了RESTFul的部分實踐原則,並非全部。 給出一個典型的RESTFul API設計風格:

以上URL非常容易理解,分頁獲取最新若干的Product資源。

最後,我們想聊一下,RESTFul API到底好用嗎?某些情況好用,某些情況非常不好用。什麼情況好用,什麼情況不好用呢?
我的一個經驗性的總結:對於開放的API,豆瓣、新浪微博、GitHub,好用,非常合適;對於內部開發,不好用。
基於資源型的RESTFul API 介面粒度和返回結果過於的“粗”,它通常返回的都是完整的資料模型,這對於客戶端非常不友好。但開放API之所以開放,就是因為它不知道你到底需要什麼返回結果,既然不知道,那麼我乾脆都返回給你。這樣的好處是通用,但客戶端不好處理。你只需要一個欄位,伺服器啪的丟給你十幾個,作為客戶端開發者你怎麼想?

內部開發由於需求非常明確,通常來說伺服器是不應該簡單粗暴的直接甩資源實體給客戶端的。那RESTFul API就不能接入到內部開發嗎?當然不是,我們需要靈活一些借鑑RESTFul中的優點,來設計我們的內部API。那麼如何簡化,這就不是一篇文章能夠說清楚的了,也沒有一個統一的標準,需要自己去琢磨和體會。

最後舉個例子吧,我個人在開發內部介面時會保留絕大多數的REST 特性,但我不會嚴格的只寫增、刪、改、查四個介面。必要的時候,還是要靈活處理一下。而且錯誤碼、狀態碼這些非常優秀的特性,必須保留。

好了,關於RESTFul我們就介紹到這裡。特別強調,介面設計是一個非常依賴於經驗和重構的技術活兒,設計介面需要有一些藝術家的天賦(真實體會),你看GitHub的介面就非常的“美”。不要覺得很簡單,真的比寫程式碼還難。難道大家不覺得,有時候起名字真的是一件很難的事兒嘛?