REST以及RESTful理解

1、傳統下的API接口
       http是目前在互聯網上使用最多的協議,沒有之一。 
  但是http的創始人一直都以爲,在過去10幾年來,全部的人都在錯誤的使用Http.這句話怎麼說呢? 
  若是說你要刪除一個數據,以往的作法一般是 delete/{id}  
  若是你要更新一個數據,多是Post數據放Body,而後方法是 update/{id}, 或者是artichle/{id}?method=update  
    這種作法讓Roy Fielding很暴燥,他以爲這個世界不應這樣的,全部的人都在誤解並且在嚴重錯誤的誤解Http的設計初衷,比如是發明了火藥卻只用它來作煙花爆竹。 
   那麼正確的使用方式是什麼呢?若是你要看Rest各類特性,你恐怕真的很難理解Rest,可是若是你看錯誤的使用http的人倒底兒了哪些錯,什麼是Rest就特別容易理解了。  前端

第一條.混亂 web

   一萬我的內心有一萬個Url的命名規則,Url是統一資源定位符,重點是資源。而不少人卻把它當成了萬金油,每個獨立的虛擬的網頁均可以隨意使用,各類操做都可以迭加。這是混亂的來源之一。 
好比:json

https://localhost:8080/myweb/getUserById?id=1
https://localhost:8080/myweb/user/getById?id=1
https://localhost:8080/myweb/x/y?id=1
第二條.貪婪後端

  有狀態和無狀態所有混在一塊兒。特別是在購物車或者是登陸的應用中,常常刷新就丟失帶來的用戶體驗簡直棒棒噠。每個請求並不能單獨的響應一些功能,不少的功能混雜在一塊兒裏。這是人性貪婪的本質,也是各類Hack的起源,只要可以把問題解決掉,總會有人用他認爲最方便的方式去解決問題,好比說汽車門把手壞掉了直接系根繩子當把手,emmmm這樣確實很棒啊。 
   
第三條.無序api

  返回的結果每每是很隨意,各類錯誤信息原本就是用Http的狀態碼構成的,但是不少人仍是喜歡把錯誤信息返回在返回值中。最多見的就是Code和Message,固然對於這一點,我我的是保留疑問的,個人觀點是,Http自己的錯誤和服務器的內部錯誤仍是須要在不斷層面分開的,不能混在一塊兒。但是在大神眼裏並不是如此。瀏覽器

那麼怎麼解決這些問題呢? 緩存

強迫症患者的福音就是先頒規則,第一個規則就是明確Url是什麼,該怎麼用。就是全部的Url本質來說,都應該是一種資源。一個獨立的Url地址,就是對應一個獨一無二的資源。怎麼樣?這種感受是否是棒棒噠?一個冰淇淋,一個老師,一間房子,在Url上對應的都是一個資源,不會有多餘的Url跟他對應,也不會表示有多個Url地址  
  注意,這裏點的是Url地址,並非單獨的參數,他就是一個/room/{room_id}這樣的東西,舉個栗子,/room/3242 這就表示3242號房間。這是一個清爽的世界啊,你想一想,以前的Url是什麼都要,我開房,多是/open/room/3242 我要退房多是/exit/3242/room,我要打理房間,多是room/3242?method=clean.夠了!這些亂七八糟的東西全夠了,讓世界迴歸清爽的本質,一間房,就是/room/3242 沒有別的Url地址了。 
  在過去的混亂世界裏,常常用的就是Get和Post。若是不是由於Get不支持大數據傳輸,我想連Post都不會有人使用。(想像一下Roy Fielding在憤怒的對着電腦屏幕喊,Http的Method一共有八個,大家爲毛只逮着Get一隻羊的毛薅薅薅薅薅)。服務器

  而對資源最多見的操做是什麼?CRUD,對不對,就是建立,讀,更新,刪除。再看Http的Method?是否是很是完美?其實也怪Fielding老爺子一開始命名不許確,若是剛開始就是把Get方法叫作Read,Put方法叫作Update,Post叫作Create這該多好。。。 
  你用一個Get,你們又發現沒什麼限制沒什麼所謂,又很難理解Put和Post的差異,法無禁止便可爲啊,呃,老爺子不要瞪我,我瞎說的。總之,這四種方法夠不夠你浪?你有自己找出來更多的對資源的操做來啊,我還有4個Method沒用過呢。若是這4個真的不夠了,有什麼問題,大不了我再從新更改http協議啊。其實簡單說,對於Rest理解到這裏就夠了。後續的東西,都是在這一條基礎上空想出來的,比強迫症更強迫症,固然,無狀態我是百分百支持的。以上的各類表述可能不太準確,也純屬是個人意淫和各類小道資料,並未考據,可是憑良心講,我是早就看不慣黑暗年代裏的Url命名風格了,因此當時最先接觸到Rest的時候,瞬間就找到了真愛,我靠,這不就是我一直想要的答案嗎?可是我一直想的僅僅是命名規範,歷來沒有把本身的思考角度放在一個url就是一個資源,全部的操做都是對資源的更改而言的角度上啊。因此你能理解到的程度,更多的就是在於你要弄清楚你要解決的什麼問題,若是你的問題只是理解Rest,恐怕你很理解,若是你的問題是怎麼解決Url混亂的問題,你反而很快能弄懂了~restful

2、對比
https://localhost:8080/myweb/getDogs --> GET /rest/api/dogs 獲取全部小狗狗 
https://localhost:8080/myweb/addDogs --> POST /rest/api/dogs 添加一個小狗狗 
https://localhost:8080/myweb/updateDogs/:dog_id --> PUT /rest/api/dogs/:dog_id 修改一個小狗狗 
https://localhost:8080/myweb/deleteDogs/:dog_id --> DELETE /rest/api/dogs/:dog_id 刪除一個小狗狗

左邊是咱們寫的,並且後臺咱們可能會寫出不少返回值,並且各類各樣的,好比 
https://localhost:8080/myweb/addDogs架構

操做成功 或者 1
1
或者

操做失敗 或者 0
1
這還要咱們本身去解析,還要前端和後端去協商你返回的0是啥意識啊。可是REST返回值是標準的,好比

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxx

{
   "url" : "/api/categories/1",
   "label" : "Food",
   "items_url" : "/api/items?category=1",
   "brands" : [
         {
            "label" : "友臣",
            "brand_key" : "32073",
            "url" : "/api/brands/32073"
         }, {
            "label" : "樂事",
            "brand_key" : "56632",
            "url" : "/api/brands/56632"
         }
         ...
   ]
}

格式固定,第一行永遠是操做失敗或者成功的狀態碼,第二行是返回的類型,第三行內容的長度,第五行開始是內容。

這樣我只需寫一個程序解析返回的信息就能夠了,能夠重用,可是咱們上面傳統的不只僅要協商,還有有不一樣的解析程序,稍微改變,就不能正常使用了。因此rest的明顯更加通用。

例子

一、獲取文章

請求:
GET /blog/post/{postId} HTTP/1.1

響應:
HTTP/1.1 200 OK
{
    "title": "foobar",
    "content": "foobar",
    "comments": ["", "", ""]
}

二、發佈文章

請求:
POST /blog/post HTTP/1.1
{
    "title": "foobar",
    "content": "foobar",
    "comments": ["", "", ""]
}

響應:
HTTP/1.1 201 CREATED


3、規則
GET    用來獲取資源,
POST  用來新建資源(也能夠用於更新資源),
PUT    用來更新資源,
DELETE  用來刪除資源

例子

DELETE http://api.qc.com/v1/friends: 刪除某人的好友 (在http parameter指定好友id)
POST http://api.qc.com/v1/friends: 添加好友UPDATE 
http://api.qc.com/v1/profile: 更新我的資料

4、概念
REST 是面向資源的,這個概念很是重要,而資源是經過 URI 進行暴露。 
URI 的設計只要負責把資源經過合理方式暴露出來就能夠了。對資源的操做與它無關,操做是經過 HTTP動詞來體現,因此REST 經過 URI 暴露資源時,會強調不要在 URI 中出現動詞。

好比:左邊是錯誤的設計,而右邊是正確的

GET /rest/api/getDogs --> GET /rest/api/dogs 獲取全部小狗狗 
GET /rest/api/addDogs --> POST /rest/api/dogs 添加一個小狗狗 
GET /rest/api/editDogs/:dog_id --> PUT /rest/api/dogs/:dog_id 修改一個小狗狗 
GET /rest/api/deleteDogs/:dog_id --> DELETE /rest/api/dogs/:dog_id 刪除一個小狗狗

REST很好地利用了HTTP自己就有的一些特徵,如HTTP動詞、HTTP狀態碼、HTTP報頭等等 
REST API 是基於 HTTP的,因此你的API應該去使用 HTTP的一些標準。這樣全部的HTTP客戶端(如瀏覽器)纔可以直接理解你的API(固然還有其餘好處,如利於緩存等等)。REST 實際上也很是強調應該利用好 HTTP原本就有的特徵,而不是隻把 HTTP當成一個傳輸層這麼簡單了。

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxx

{
   "url" : "/api/categories/1",
   "label" : "Food",
   "items_url" : "/api/items?category=1",
   "brands" : [
         {
            "label" : "友臣",
            "brand_key" : "32073",
            "url" : "/api/brands/32073"
         }, {
            "label" : "樂事",
            "brand_key" : "56632",
            "url" : "/api/brands/56632"
         }
         ...
   ]
}

看這個響應,包含了http裏面的狀態碼等信息。還會有http的一些報頭。

Authorization 認證報頭 
Cache-Control 緩存報頭 
Cnotent-Type  消息體類型報頭 
......

5、REST 系統的特徵
客戶-服務器(Client-Server),提供服務的服務器和使用服務的客戶須要被隔離對待。
無狀態(Stateless),來自客戶的每個請求必須包含服務器處理該請求所需的全部信息。換句話說,服務器端不能存儲來自某個客戶的某個請求中的信息,並在該客戶的其餘請求中使用。
可緩存(Cachable),服務器必須讓客戶知道請求是否能夠被緩存。(Ross:更詳細解釋請參考 理解本真的REST架構風格 以及 StackOverflow 的這個問題 中對緩存的解釋。)
分層系統(Layered System),服務器和客戶之間的通訊必須被這樣標準化:容許服務器和客戶之間的中間層(Ross:代理,網關等)能夠代替服務器對客戶的請求進行迴應,並且這些對客戶來講不須要特別支持。
統一接口(Uniform Interface),客戶和服務器之間通訊的方法必須是統一化的。(Ross:GET,POST,PUT.DELETE, etc)
支持按需代碼(Code-On-Demand,可選),服務器能夠提供一些代碼或者腳本(Ross:Javascrpt,flash,etc)並在客戶的運行環境中執行。這條準則是這些準則中惟一沒必要必須知足的一條。(Ross:好比客戶能夠在客戶端下載腳本生成密碼訪問服務器。)
詳細解釋

無狀態(Stateless)

   所謂無狀態的,即全部的資源,均可以經過URI定位,並且這個定位與其餘資源無關,也不會由於其餘資源的變化而改變。有狀態和無狀態的區別,舉個簡單的例子說明一下。如查詢員工的工資,若是查詢工資是須要登陸系統,進入查詢工資的頁面,執行相關操做後,獲取工資的多少,則這種狀況是有狀態的,由於查詢工資的每一步操做都依賴於前一步操做,只要前置操做不成功,後續操做就沒法執行;若是輸入一個url便可獲得指定員工的工資,則這種狀況是無狀態的,由於獲取工資不依賴於其餘資源或狀態,且這種狀況下,員工工資是一個資源,由一個url與之對應,能夠經過HTTP中的GET方法獲得資源,這是典型的RESTful風格。

这里写图片描述 

 

6、統一接口(Uniform Interface)

  RESTful架構風格規定,數據的元操做,即CRUD(create, read, update和delete,即數據的增刪查改)操做,分別對應於HTTP方法:GET用來獲取資源,POST用來新建資源(也能夠用於更新資源),PUT用來更新資源,DELETE用來刪除資源,這樣就統一了數據操做的接口,僅經過HTTP方法,就能夠完成對數據的全部增刪查改工做。

即:

GET(SELECT):從服務器取出資源(一項或多項)。
POST(CREATE):在服務器新建一個資源。
PUT(UPDATE):在服務器更新資源(客戶端提供完整資源數據)。
PATCH(UPDATE):在服務器更新資源(客戶端提供須要修改的資源數據)。
DELETE(DELETE):從服務器刪除資源。

演化
https://zhuanlan.zhihu.com/p/30396391?group_id=937244108725641216

優勢&缺點
優勢是由於他對uri進行了限制,只用於定義資源。這樣看起來比較容易理解。尤爲是對簡單的對象的增刪改查,很好理解。

缺點是由於這種限制,致使設計uri變得複雜了。尤爲是複雜的關係,操做,資源集合,硬性套用rest原則設計很是困難。在rest基礎上的HATEOAS,返回的json裏增長了相應的關係和url。這也一樣帶來問題。好處是對簡單的關係,的確能夠經過url進一步處理。但對複雜的關係和操做,HATEOAS並不能勝任描述。反而在單純的數據中增長了一堆垃圾信息。

是什麼?
REST是一個標準,一種規範,遵循REST風格可使開發的接口通用,便於調用者理解接口的做用。

參考:  https://www.zhihu.com/question/28557115  https://blog.igevin.info/posts/restful-architecture-in-general/  

相關文章
相關標籤/搜索