我經常會面試一些做PHP的開發者,讓我很奇怪的是,10個人總有8個多不知道什麼是REST服務,甚至是沒有聽說過。但RESTFul API已經是現在網際網路裡對外開放接口的主流模式,可參考:
豆瓣API https://developers.douban.com/wiki/?title=api_v2
GitHub https://developer.github.com/v3/
數一數年限,據我接觸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設計風格:
https://api.z.cn/v1/product/recent?page=3&size=20
以上URL非常容易了解,分頁擷取最新若幹的Product資源。
最後,我們想聊一下,RESTFul API到底好用嗎?某些情況好用,某些情況非常不好用。什麼情況好用,什麼情況不好用呢?
我的一個經驗性的總結:對于開放的API,豆瓣、新浪微網誌、GitHub,好用,非常合适;對于内部開發,不好用。
基于資源型的RESTFul API 接口粒度和傳回結果過于的“粗”,它通常傳回的都是完整的資料模型,這對于用戶端非常不友好。但開放API之是以開放,就是因為它不知道你到底需要什麼傳回結果,既然不知道,那麼我幹脆都傳回給你。這樣的好處是通用,但用戶端不好處理。你隻需要一個字段,伺服器啪的丢給你十幾個,作為用戶端開發者你怎麼想?
内部開發由于需求非常明确,通常來說伺服器是不應該簡單粗暴的直接甩資源實體給用戶端的。那RESTFul API就不能接入到内部開發嗎?當然不是,我們需要靈活一些借鑒RESTFul中的優點,來設計我們的内部API。那麼如何簡化,這就不是一篇文章能夠說清楚的了,也沒有一個統一的标準,需要自己去琢磨和體會。
最後舉個例子吧,我個人在開發内部接口時會保留絕大多數的REST 特性,但我不會嚴格的隻寫增、删、改、查四個接口。必要的時候,還是要靈活處理一下。而且錯誤碼、狀态碼這些非常優秀的特性,必須保留。
好了,關于RESTFul我們就介紹到這裡。特别強調,接口設計是一個非常依賴于經驗和重構的技術活兒,設計接口需要有一些藝術家的天賦(真實體會),你看GitHub的接口就非常的“美”。不要覺得很簡單,真的比寫代碼還難。難道大家不覺得,有時候起名字真的是一件很難的事兒嘛?
本文原創釋出于慕課網 ,轉載請注明出處,謝謝合作!
作者: 7七月