前言:restful出現(xiàn)的環(huán)境,什么是rest?以及出現(xiàn)的意義
1.REST的由來
全稱:REST,全稱是Resource Representational State Transfer,即:資源在網(wǎng)絡(luò)中以某種形式進(jìn)行狀態(tài)轉(zhuǎn)移。————所謂狀態(tài)的轉(zhuǎn)移,它首次出現(xiàn)在2000年Roy Fielding的博士論文中,Roy Fielding是HTTP規(guī)范的主要編寫者之一。 他在論文中提到:"我這篇文章的寫作目的,就是想在符合架構(gòu)原理的前提下,理解和評估以網(wǎng)絡(luò)為基礎(chǔ)的應(yīng)用軟件的架構(gòu)設(shè)計(jì),得到一個(gè)功能強(qiáng)、性能好、適宜通信的架構(gòu)。REST指的是一組架構(gòu)約束條件和原則。" 如果一個(gè)架構(gòu)符合REST的約束條件和原則,我們就稱它為RESTful架構(gòu)。
REST本身并沒有創(chuàng)造新的技術(shù)、組件或服務(wù),而隱藏在RESTful背后的理念就是使用Web的現(xiàn)有特征和能力, 更好地使用現(xiàn)有Web標(biāo)準(zhǔn)中的一些準(zhǔn)則和約束。雖然REST本身受Web技術(shù)的影響很深, 但是理論上REST架構(gòu)風(fēng)格并不是綁定在HTTP上,只不過目前HTTP是唯一與REST相關(guān)的實(shí)例。 所以我們這里描述的REST也是通過HTTP實(shí)現(xiàn)的REST。
Web 應(yīng)用程序最重要的 REST 原則是,客戶端和服務(wù)器之間的交互在請求之間是無狀態(tài)的。從客戶端到服務(wù)器的每個(gè)請求都必須包含理解請求所必需的信息。如果服務(wù)器在請求之間的任何時(shí)間點(diǎn)重啟,客戶端不會得到通知。此外,無狀態(tài)請求可以由任何可用服務(wù)器回答,這十分適合云計(jì)算之類的環(huán)境??蛻舳丝梢跃彺鏀?shù)據(jù)以改進(jìn)性能。
在服務(wù)器端,應(yīng)用程序狀態(tài)和功能可以分為各種資源。資源是一個(gè)有趣的概念實(shí)體,它向客戶端公開。資源的例子有:應(yīng)用程序?qū)ο?、?shù)據(jù)庫記錄、算法等等。每個(gè)資源都使用 URI (Universal Resource Identifier) 得到一個(gè)惟一的地址。所有資源都共享統(tǒng)一的界面,以便在客戶端和服務(wù)器之間傳輸狀態(tài)。使用的是標(biāo)準(zhǔn)的 HTTP 方法,比如 GET、PUT、POST 和 DELETE。Hypermedia 是應(yīng)用程序狀態(tài)的引擎,資源表示通過超鏈接互聯(lián)。
另一個(gè)重要的 REST 原則是分層系統(tǒng),這表示組件無法了解它與之交互的中間層以外的組件。通過將系統(tǒng)知識限制在單個(gè)層,可以限制整個(gè)系統(tǒng)的復(fù)雜性,促進(jìn)了底層的獨(dú)立性。
REST 描述了一個(gè)架構(gòu)樣式的互聯(lián)系統(tǒng)(如 Web 應(yīng)用程序)。REST 約束條件作為一個(gè)整體應(yīng)用時(shí),將生成一個(gè)簡單、可擴(kuò)展、有效、安全、可靠的架構(gòu)。由于它簡便、輕量級以及通過 HTTP 直接傳輸數(shù)據(jù)的特性,RESTful Web 服務(wù)成為基于 SOAP 服務(wù)的一個(gè)最有前途的替代方案。用于 web 服務(wù)和動態(tài) Web 應(yīng)用程序的多層架構(gòu)可以實(shí)現(xiàn)可重用性、簡單性、可擴(kuò)展性和組件可響應(yīng)性的清晰分離。開發(fā)人員可以輕松使用 Ajax 和 RESTful Web 服務(wù)一起創(chuàng)建豐富的界面。
出現(xiàn):REST最早是由Roy Fielding博士發(fā)表的論文中提到的,他也曾參與設(shè)計(jì)了HTTP協(xié)議。論文地址:http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
定義:簡單來說REST是一種系統(tǒng)架構(gòu)設(shè)計(jì)風(fēng)格(而非標(biāo)準(zhǔn)),一種分布式系統(tǒng)的應(yīng)用層解決方案。REST 指的是一組架構(gòu)約束條件和原則。滿足這些約束條件和原則的應(yīng)用程序或設(shè)計(jì)就是 RESTful。
Resource:資源,即數(shù)據(jù)。
?Representational:某種表現(xiàn)形式,比如用JSON,XML,JPEG等;
?State Transfer:狀態(tài)變化。通過HTTP動詞實(shí)現(xiàn)。
背景:早期的網(wǎng)頁端是前后臺一起的,比如PHP、JSP等。而隨著近幾年移動端的快速發(fā)展和分布式架構(gòu)的應(yīng)用,各種Client層出不窮,這個(gè)時(shí)候就需要有個(gè)統(tǒng)一的機(jī)制,來為前后端通信提供服務(wù)。
? ? ?而RESTful API就是目前比較成熟的的一套應(yīng)用程序API設(shè)計(jì)理論。
目的:Client和Server端進(jìn)一步解耦。
應(yīng)用:最為經(jīng)典的莫過于github API。
2.什么是服務(wù)?
任何業(yè)務(wù)服務(wù)都可以抽象為對象的狀態(tài)維護(hù),基本操作就増刪查改四種.
例如:
訪問文章的,很明顯就是對文章及其列表的增刪查改,文章是被做操的對象,通過增刪查改修改文章的狀態(tài).
銀行轉(zhuǎn)賬,好像是有邏輯行為,但實(shí)際上每個(gè)轉(zhuǎn)賬事務(wù),可以理解為對一個(gè)賬單對象的狀態(tài)操作,這個(gè)賬單又關(guān)聯(lián)了多個(gè)賬戶的狀態(tài).
現(xiàn)實(shí)生活中一個(gè)人走路,是一個(gè)明顯的對象行為,也可以表示為人這個(gè)對象從位置A經(jīng)過時(shí)間T后變?yōu)槲恢肂的狀態(tài)更新操作.
服務(wù)端無論使用何種架構(gòu),加入緩存,隊(duì)列,數(shù)據(jù)庫,最終的目標(biāo)就是維護(hù)資源的狀態(tài).
從客戶端的視角來看,服務(wù)端API描述的內(nèi)容就是其維護(hù)的對象的瞬時(shí)狀態(tài)的表現(xiàn).
3.Restful的理解
一種軟件架構(gòu)風(fēng)格、設(shè)計(jì)風(fēng)格,而不是標(biāo)準(zhǔn),只是提供了一組設(shè)計(jì)原則和約束條件。它主要用于客戶端和服務(wù)器交互類的軟件?;谶@個(gè)風(fēng)格設(shè)計(jì)的軟件可以更簡潔,更有層次,更易于實(shí)現(xiàn)緩存等機(jī)制。
RESTful架構(gòu),就是目前最流行的一種互聯(lián)網(wǎng)軟件架構(gòu)。它結(jié)構(gòu)清晰、符合標(biāo)準(zhǔn)、易于理解、擴(kuò)展方便,所以正得到越來越多網(wǎng)站的采用。
RESTful?是目前最流行的 API 設(shè)計(jì)規(guī)范,用于 Web 數(shù)據(jù)接口的設(shè)計(jì)。傳統(tǒng)上,軟件和網(wǎng)絡(luò)是兩個(gè)不同的領(lǐng)域,很少有交集;軟件開發(fā)主要針對單機(jī)環(huán)境,網(wǎng)絡(luò)則主要研究系統(tǒng)之間的通信。在當(dāng)今的互聯(lián)網(wǎng)應(yīng)用的前端展示媒介很豐富。有手機(jī)、有平板電腦還有PC以及其他的展示媒介。那么這些前端接收到的用戶請求統(tǒng)一由一個(gè)后臺來處理并返回給不同的前端肯定是最科學(xué)和最經(jīng)濟(jì)的方式,RESTful API就是一套協(xié)議來規(guī)范多種形式的前端和同一個(gè)后臺的交互方式.
一.資源與URI
二.統(tǒng)一資源接口
三.資源的表述
四.資源的鏈接
五.狀態(tài)的轉(zhuǎn)移
(1).為什么是RESTful
服務(wù)端面向Web的API需要通過HTTP協(xié)議來表達(dá).了解一下REST的起源可以知道其作者是HTTP協(xié)議的制定者,所以HTTP協(xié)議的語義元素天然符合REST的約束要求.但RESTful并不是強(qiáng)制的,Web API不必遵循RESTful,但是遵循RESTful可以令A(yù)PI表達(dá)的語義更簡單清晰統(tǒng)一,在語義全部抽象為轉(zhuǎn)臺轉(zhuǎn)移后,分布式系統(tǒng)的架構(gòu)關(guān)注點(diǎn)(維護(hù)狀態(tài)一致)也會更明確.前后端分離主要是以API為界限進(jìn)行解耦的,這就會產(chǎn)生大量的API,采用RESTful來設(shè)計(jì)API主要有以下好處:
一、表現(xiàn)力更強(qiáng),更易于理解
二、RESRful是無狀態(tài),所以不管前端是何種設(shè)備何種狀態(tài)都可以無差別的請求資源
(2).RESTful的初級內(nèi)容
一.使用METHOD (POST,DELETE,GET,PUT) 等動詞表示増刪查改四種操作.
二.使用URI(通常是其子集URL)來表示對象或資源.
三.使用queryString表示查詢輸入
四.使用body表示更新和保存的狀態(tài)輸入
五.使用HEAD進(jìn)行擴(kuò)展
(3).怎么用RESTful
一、每個(gè)資源使用2個(gè)URL,網(wǎng)址中只能有名詞
二、對于資源的操作類型由HTTP動詞來表示
三、統(tǒng)一的返回結(jié)果
四、返回正確的狀態(tài)碼
五、允許通過HTTP內(nèi)容協(xié)商,建議格式預(yù)定義為JSON
六、對可選發(fā)雜的參數(shù),使用查詢字符串(?)
七、返回有用的錯誤信息(message)
八、非資源請求用動詞,這看起似乎和1中的說法有矛盾,但這里指的是非資源,而不是資源
(4).RESTful架構(gòu)優(yōu)點(diǎn):
一.前后端分離,減少流量
二.安全問題集中在接口上,由于接受json格式,防止了注入型等安全問題
三.前端無關(guān)化,后端只負(fù)責(zé)數(shù)據(jù)處理,前端表現(xiàn)方式可以是任何前端語言(android,ios,html5)
四.前端和后端人員更加專注于各自開發(fā),只需接口文檔便可完成前后端交互,無需過多相互了解
五.服務(wù)器性能優(yōu)化:由于前端是靜態(tài)頁面,通過nginx便可獲取,服務(wù)器主要壓力放在了接口上
4.RESTful api 規(guī)范以及設(shè)計(jì)原則
(1)URL 設(shè)計(jì)(資源與URI)
REST全稱是表述性狀態(tài)轉(zhuǎn)移,那究竟指的是什么的表述? 其實(shí)指的就是資源。任何事物,只要有被引用到的必要,它就是一個(gè)資源。資源可以是實(shí)體(例如手機(jī)號碼),也可以只是一個(gè)抽象概念(例如價(jià)值) 。下面是一些資源的例子:
某用戶的手機(jī)號碼
某用戶的個(gè)人信息
最多用戶訂購的GPRS套餐
兩個(gè)產(chǎn)品之間的依賴關(guān)系
某用戶可以辦理的優(yōu)惠套餐
某手機(jī)號碼的潛在價(jià)值
要讓一個(gè)資源可以被識別,需要有個(gè)唯一標(biāo)識,在Web中這個(gè)唯一標(biāo)識就是URI(Uniform Resource Identifier)。
URI既可以看成是資源的地址,也可以看成是資源的名稱。如果某些信息沒有使用URI來表示,那它就不能算是一個(gè)資源, 只能算是資源的一些信息而已。URI的設(shè)計(jì)應(yīng)該遵循可尋址性原則,具有自描述性,需要在形式上給人以直覺上的關(guān)聯(lián)。
一.? ? 使用_或-來讓URI可讀性更好
二.? ? 使用/來表示資源的層級關(guān)系
三.? ? ?使用?用來過濾資源
四.? ? ,或;可以用來表示同級資源的關(guān)系
1.1 動詞 + 賓語
RESTful 的核心思想就是,客戶端發(fā)出的數(shù)據(jù)操作指令都是"動詞 + 賓語"的結(jié)構(gòu)。比如,GET /articles這個(gè)命令,GET是動詞,/articles是賓語。
動詞通常就是五種 HTTP 方法,對應(yīng) CRUD 操作。

根據(jù) HTTP 規(guī)范,動詞一律大寫。
1.2 動詞的覆蓋
有些客戶端只能使用GET和POST這兩種方法。服務(wù)器必須接受POST模擬其他三個(gè)方法(PUT、PATCH、DELETE)。
這時(shí),客戶端發(fā)出的 HTTP 請求,要加上X-HTTP-Method-Override屬性,告訴服務(wù)器應(yīng)該使用哪一個(gè)動詞,覆蓋POST方法。

上面代碼中,X-HTTP-Method-Override指定本次請求的方法是PUT,而不是POST。
1.3 賓語必須是名詞
賓語就是 API 的 URL,是 HTTP 動詞作用的對象。它應(yīng)該是名詞,不能是動詞。比如,/articles這個(gè) URL 就是正確的,而下面的 URL 不是名詞,所以都是錯誤的。

1.4 復(fù)數(shù) URL
既然 URL 是名詞,那么應(yīng)該使用復(fù)數(shù),還是單數(shù)?
這沒有統(tǒng)一的規(guī)定,但是常見的操作是讀取一個(gè)集合,比如GET /articles(讀取所有文章),這里明顯應(yīng)該是復(fù)數(shù)。
為了統(tǒng)一起見,建議都使用復(fù)數(shù) URL,比如GET /articles/2要好于GET /article/2。
1.5 避免多級 URL
常見的情況是,資源需要多級分類,因此很容易寫出多級的 URL,比如獲取某個(gè)作者的某一類文章。
GET /authors/12/categories/2
這種 URL 不利于擴(kuò)展,語義也不明確,往往要想一會,才能明白含義。
更好的做法是,除了第一級,其他級別都用查詢字符串表達(dá)。
GET /authors/12?categories=2
下面是另一個(gè)例子,查詢已發(fā)布的文章。你可能會設(shè)計(jì)成下面的 URL。
GET /articles/published
查詢字符串的寫法明顯更好。
GET /articles?published=true
?(2)統(tǒng)一資源接口(狀態(tài)碼)
RESTful風(fēng)格的數(shù)據(jù)元操CRUD(create,read,update,delete)分別對應(yīng)HTTP方法:GET用來獲取資源,POST用來新建資源(也可以用于更新資源),PUT用來更新資源,DELETE用來刪除資源,這樣就統(tǒng)一了數(shù)據(jù)操作的接口。
RESTful架構(gòu)應(yīng)該遵循統(tǒng)一接口原則(如上),統(tǒng)一接口包含了一組受限的預(yù)定義的操作,不論什么樣的資源,都是通過使用相同的接口進(jìn)行資源的訪問。接口應(yīng)該使用標(biāo)準(zhǔn)的HTTP方法如GET,PUT和POST,并遵循這些方法的語義。
果按照HTTP方法的語義來暴露資源,那么接口將會擁有安全性和冪等性的特性,例如GET和HEAD請求都是安全的, 無論請求多少次,都不會改變服務(wù)器狀態(tài)。而GET、HEAD、PUT和DELETE請求都是冪等的,無論對資源操作多少次, 結(jié)果總是一樣的,后面的請求并不會產(chǎn)生比第一次更多的影響。
一.下面列出了GET,DELETE,PUT和POST的典型用法:
1.GET
安全且冪等
獲取表示
變更時(shí)獲取表示(緩存)
200(OK) - 表示已在響應(yīng)中發(fā)出
204(無內(nèi)容) - 資源有空表示
301(Moved Permanently) - 資源的URI已被更新
303(See Other) - 其他(如,負(fù)載均衡)
304(not modified)- 資源未更改(緩存)
400 (bad request)- 指代壞請求(如,參數(shù)錯誤)
404 (not found)- 資源不存在
406 (not acceptable)- 服務(wù)端不支持所需表示
500 (internal server error)- 通用錯誤響應(yīng)
503 (Service Unavailable)- 服務(wù)端當(dāng)前無法處理請求
2.POST
不安全且不冪等
使用服務(wù)端管理的(自動產(chǎn)生)的實(shí)例號創(chuàng)建資源
創(chuàng)建子資源
部分更新資源
如果沒有被修改,則不過更新資源(樂觀鎖)
200(OK)- 如果現(xiàn)有資源已被更改
201(created)- 如果新資源被創(chuàng)建
202(accepted)- 已接受處理請求但尚未完成(異步處理)
301(Moved Permanently)- 資源的URI被更新
303(See Other)- 其他(如,負(fù)載均衡)
400(bad request)- 指代壞請求
404 (not found)- 資源不存在
406 (not acceptable)- 服務(wù)端不支持所需表示
409 (conflict)- 通用沖突
412 (Precondition Failed)- 前置條件失?。ㄈ鐖?zhí)行條件更新時(shí)的沖突)
415 (unsupported media type)- 接受到的表示不受支持
500 (internal server error)- 通用錯誤響應(yīng)
503 (Service Unavailable)- 服務(wù)當(dāng)前無法處理請求
3.PUT
不安全但冪等
用客戶端管理的實(shí)例號創(chuàng)建一個(gè)資源
通過替換的方式更新資源
如果未被修改,則更新資源(樂觀鎖)
200 (OK)- 如果已存在資源被更改
201 (created)- 如果新資源被創(chuàng)建
301(Moved Permanently)- 資源的URI已更改
303 (See Other)- 其他(如,負(fù)載均衡)
400 (bad request)- 指代壞請求
404 (not found)- 資源不存在
406 (not acceptable)- 服務(wù)端不支持所需表示
409 (conflict)- 通用沖突
412 (Precondition Failed)- 前置條件失敗(如執(zhí)行條件更新時(shí)的沖突)
415 (unsupported media type)- 接受到的表示不受支持
500 (internal server error)- 通用錯誤響應(yīng)
503 (Service Unavailable)- 服務(wù)當(dāng)前無法處理請求
4.DELETE
不安全但冪等
刪除資源
200 (OK)- 資源已被刪除
301 (Moved Permanently)- 資源的URI已更改
303 (See Other)- 其他,如負(fù)載均衡
400 (bad request)- 指代壞請求
404 (not found)- 資源不存在
409 (conflict)- 通用沖突
500 (internal server error)- 通用錯誤響應(yīng)
503 (Service Unavailable)- 服務(wù)端當(dāng)前無法處理請求
2.HTTP 狀態(tài)碼就是一個(gè)三位數(shù),分成五個(gè)類別。
1.? ? 1xx:相關(guān)信息
2.? ? ?2xx:操作成功
3.? ? ?3xx:重定向
4.? ? ?4xx:客戶端錯誤
5.? ? ?5xx:服務(wù)器錯誤
2.1? ? ? 200狀態(tài)碼表示操作成功,但是不同的方法可以返回更精確的狀態(tài)碼。
1.? ?GET: 200 OK
2.? ?POST: 201 Created
3.? ?PUT: 200 OK
4.? ?PATCH: 200 OK
5.? ?DELETE: 204 No Content
上面代碼中,POST返回201狀態(tài)碼,表示生成了新的資源;DELETE返回204狀態(tài)碼,表示資源已經(jīng)不存在。
2.2? ? ? ?3xx 狀態(tài)碼
API 用不到301狀態(tài)碼(永久重定向)和302狀態(tài)碼(暫時(shí)重定向,307也是這個(gè)含義),因?yàn)樗鼈兛梢杂蓱?yīng)用級別返回,瀏覽器會直接跳轉(zhuǎn),API 級別可以不考慮這兩種情況。
API 用到的3xx狀態(tài)碼,主要是303 See Other,表示參考另一個(gè) URL。它與302和307的含義一樣,也是"暫時(shí)重定向",區(qū)別在于302和307用于GET請求,而303用于POST、PUT和DELETE請求。收到303以后,瀏覽器不會自動跳轉(zhuǎn),而會讓用戶自己決定下一步怎么辦。
2.3? ? ? ?4xx 狀態(tài)碼
4xx狀態(tài)碼表示客戶端錯誤,主要有下面幾種。
400 Bad Request:服務(wù)器不理解客戶端的請求,未做任何處理。
401 Unauthorized:用戶未提供身份驗(yàn)證憑據(jù),或者沒有通過身份驗(yàn)證。
403 Forbidden:用戶通過了身份驗(yàn)證,但是不具有訪問資源所需的權(quán)限。
404 Not Found:所請求的資源不存在,或不可用。
405 Method Not Allowed:用戶已經(jīng)通過身份驗(yàn)證,但是所用的 HTTP 方法不在他的權(quán)限之內(nèi)。
410 Gone:所請求的資源已從這個(gè)地址轉(zhuǎn)移,不再可用。
415 Unsupported Media Type:客戶端要求的返回格式不支持。比如,API 只能返回 JSON 格式,但是客戶端要求返回 XML 格式。
422 Unprocessable Entity?:客戶端上傳的附件無法處理,導(dǎo)致請求失敗。
429 Too Many Requests:客戶端的請求次數(shù)超過限額。
2.5? ? ? ? ? 5xx 狀態(tài)碼
5xx狀態(tài)碼表示服務(wù)端錯誤。一般來說,API 不會向用戶透露服務(wù)器的詳細(xì)信息,所以只要兩個(gè)狀態(tài)碼就夠了。
500 Internal Server Error:客戶端請求有效,服務(wù)器處理時(shí)發(fā)生了意外。
503 Service Unavailable:服務(wù)器無法處理請求,一般用于網(wǎng)站維護(hù)狀態(tài)。
2.6? ? 下面我們來看一些實(shí)踐中常見的問題:
POST和PUT用于創(chuàng)建資源時(shí)有什么區(qū)別?
POST和PUT在創(chuàng)建資源的區(qū)別在于,所創(chuàng)建的資源的名稱(URI)是否由客戶端決定。 例如為我的博文增加一個(gè)java的分類,生成的路徑就是分類名/categories/java,那么就可以采用PUT方法。不過很多人直接把POST、GET、PUT、DELETE直接對應(yīng)上CRUD,例如在一個(gè)典型的rails實(shí)現(xiàn)的RESTful應(yīng)用中就是這么做的。
我認(rèn)為,這是因?yàn)閞ails默認(rèn)使用服務(wù)端生成的ID作為URI的緣故,而不少人就是通過rails實(shí)踐REST的,所以很容易造成這種誤解。
客戶端不一定都支持這些HTTP方法吧?
的確有這種情況,特別是一些比較古老的基于瀏覽器的客戶端,只能支持GET和POST兩種方法。
在實(shí)踐上,客戶端和服務(wù)端都可能需要做一些妥協(xié)。例如rails框架就支持通過隱藏參數(shù)_method=DELETE來傳遞真實(shí)的請求方法, 而像Backbone這樣的客戶端MVC框架則允許傳遞_method傳輸和設(shè)置X-HTTP-Method-Override頭來規(guī)避這個(gè)問題。
統(tǒng)一接口是否意味著不能擴(kuò)展帶特殊語義的方法?
統(tǒng)一接口并不阻止你擴(kuò)展方法,只要方法對資源的操作有著具體的、可識別的語義即可,并能夠保持整個(gè)接口的統(tǒng)一性。
像WebDAV就對HTTP方法進(jìn)行了擴(kuò)展,增加了LOCK、UPLOCK等方法。而github的API則支持使用PATCH方法來進(jìn)行issue的更新
(3)服務(wù)器回應(yīng)(資源的表述)
3.1 不要返回純本文
API 返回的數(shù)據(jù)格式,不應(yīng)該是純文本,而應(yīng)該是一個(gè) JSON 對象,因?yàn)檫@樣才能返回標(biāo)準(zhǔn)的結(jié)構(gòu)化數(shù)據(jù)。所以,服務(wù)器回應(yīng)的 HTTP 頭的Content-Type屬性要設(shè)為application/json。
客戶端請求時(shí),也要明確告訴服務(wù)器,可以接受 JSON 格式,即請求的 HTTP 頭的ACCEPT屬性也要設(shè)成application/json客戶端通過HTTP方法可以獲取資源,是吧? 不,確切的說,客戶端獲取的只是資源的表述而已。 資源在外界的具體呈現(xiàn),可以有多種表述(或成為表現(xiàn)、表示)形式,在客戶端和服務(wù)端之間傳送的也是資源的表述,而不是資源本身。 例如文本資源可以采用html、xml、json等格式,圖片可以使用PNG或JPG展現(xiàn)出來。
資源的表述包括數(shù)據(jù)和描述數(shù)據(jù)的元數(shù)據(jù),例如,HTTP頭"Content-Type" 就是這樣一個(gè)元數(shù)據(jù)屬性。
那么客戶端如何知道服務(wù)端提供哪種表述形式呢?
答案是可以通過HTTP內(nèi)容協(xié)商,客戶端可以通過Accept頭請求一種特定格式的表述,服務(wù)端則通過Content-Type告訴客戶端資源的表述形式。


使用URI后綴來區(qū)分表述格式
像rails框架,就支持使用/users.xml或/users.json來區(qū)分不同的格式。 這樣的方式對于客戶端來說,無疑是更為直觀,但混淆了資源的名稱和資源的表述形式。 我個(gè)人認(rèn)為,還是應(yīng)該優(yōu)先使用內(nèi)容協(xié)商來區(qū)分表述格式。
3.2 發(fā)生錯誤時(shí),不要返回 200 狀態(tài)碼
有一種不恰當(dāng)?shù)淖龇ㄊ?,即使發(fā)生錯誤,也返回200狀態(tài)碼,把錯誤信息放在數(shù)據(jù)體里面,就像下面這樣。

上面代碼中,解析數(shù)據(jù)體以后,才能得知操作失敗。
這張做法實(shí)際上取消了狀態(tài)碼,這是完全不可取的。正確的做法是,狀態(tài)碼反映發(fā)生的錯誤,具體的錯誤信息放在數(shù)據(jù)體里面返回。下面是一個(gè)例子。

3.3 提供鏈接
API 的使用者未必知道,URL 是怎么設(shè)計(jì)的。一個(gè)解決方法就是,在回應(yīng)中,給出相關(guān)鏈接,便于下一步操作。這樣的話,用戶只要記住一個(gè) URL,就可以發(fā)現(xiàn)其他的 URL。這種方法叫做 HATEOAS。
舉例來說,GitHub 的 API 都在?api.github.com?這個(gè)域名。訪問它,就可以得到其他 URL。

上面的回應(yīng)中,挑一個(gè) URL 訪問,又可以得到別的 URL。對于用戶來說,不需要記住 URL 設(shè)計(jì),只要從 api.github.com 一步步查找就可以了。
HATEOAS 的格式?jīng)]有統(tǒng)一規(guī)定,上面例子中,GitHub 將它們與其他屬性放在一起。更好的做法應(yīng)該是,將相關(guān)鏈接與其他屬性分開。

?4 資源的鏈接
我們知道REST是使用標(biāo)準(zhǔn)的HTTP方法來操作資源的,但僅僅因此就理解成帶CURD的Web數(shù)據(jù)庫架構(gòu)就太過于簡單了。
這種反模式忽略了一個(gè)核心概念:"超媒體即應(yīng)用狀態(tài)引擎(hypermedia as the engine of application state)"。 超媒體是什么?
當(dāng)你瀏覽Web網(wǎng)頁時(shí),從一個(gè)連接跳到一個(gè)頁面,再從另一個(gè)連接跳到另外一個(gè)頁面,就是利用了超媒體的概念:把一個(gè)個(gè)把資源鏈接起來.
要達(dá)到這個(gè)目的,就要求在表述格式里邊加入鏈接來引導(dǎo)客戶端。在《RESTful Web Services》一書中,作者把這種具有鏈接的特性成為連通性。下面我們具體來看一些例子。
下面展示的是github獲取某個(gè)組織下的項(xiàng)目列表的請求,可以看到在響應(yīng)頭里邊增加Link頭告訴客戶端怎么訪問下一頁和最后一頁的記錄。 而在響應(yīng)體里邊,用url來鏈接項(xiàng)目所有者和項(xiàng)目地址。

又例如下面這個(gè)例子,創(chuàng)建訂單后通過鏈接引導(dǎo)客戶端如何去付款。

上面的例子展示了如何使用超媒體來增強(qiáng)資源的連通性。很多人在設(shè)計(jì)RESTful架構(gòu)時(shí),使用很多時(shí)間來尋找漂亮的URI,而忽略了超媒體。所以,應(yīng)該多花一些時(shí)間來給資源的表述提供鏈接,而不是專注于"資源的CRUD"。
4.1狀態(tài)的轉(zhuǎn)移
有了上面的鋪墊,再討論REST里邊的狀態(tài)轉(zhuǎn)移就會很容易理解了。
不過,我們先來討論一下REST原則中的無狀態(tài)通信原則。初看一下,好像自相矛盾了,既然無狀態(tài),何來狀態(tài)轉(zhuǎn)移一說?
其實(shí),這里說的無狀態(tài)通信原則,并不是說客戶端應(yīng)用不能有狀態(tài),而是指服務(wù)端不應(yīng)該保存客戶端狀態(tài)。
4.1.1 應(yīng)用狀態(tài)與資源狀態(tài)
實(shí)際上,狀態(tài)應(yīng)該區(qū)分應(yīng)用狀態(tài)和資源狀態(tài),客戶端負(fù)責(zé)維護(hù)應(yīng)用狀態(tài),而服務(wù)端維護(hù)資源狀態(tài)。
客戶端與服務(wù)端的交互必須是無狀態(tài)的,并在每一次請求中包含處理該請求所需的一切信息。
服務(wù)端不需要在請求間保留應(yīng)用狀態(tài),只有在接受到實(shí)際請求的時(shí)候,服務(wù)端才會關(guān)注應(yīng)用狀態(tài)。
這種無狀態(tài)通信原則,使得服務(wù)端和中介能夠理解獨(dú)立的請求和響應(yīng)。
在多次請求中,同一客戶端也不再需要依賴于同一服務(wù)器,方便實(shí)現(xiàn)高可擴(kuò)展和高可用性的服務(wù)端。
但有時(shí)候我們會做出違反無狀態(tài)通信原則的設(shè)計(jì),例如利用Cookie跟蹤某個(gè)服務(wù)端會話狀態(tài),常見的像J2EE里邊的JSESSIONID。
這意味著,瀏覽器隨各次請求發(fā)出去的Cookie是被用于構(gòu)建會話狀態(tài)的。
當(dāng)然,如果Cookie保存的是一些服務(wù)器不依賴于會話狀態(tài)即可驗(yàn)證的信息(比如認(rèn)證令牌),這樣的Cookie也是符合REST原則的。
4.1.2 應(yīng)用狀態(tài)的轉(zhuǎn)移
狀態(tài)轉(zhuǎn)移到這里已經(jīng)很好理解了, "會話"狀態(tài)不是作為資源狀態(tài)保存在服務(wù)端的,而是被客戶端作為應(yīng)用狀態(tài)進(jìn)行跟蹤的??蛻舳藨?yīng)用狀態(tài)在服務(wù)端提供的超媒體的指引下發(fā)生變遷。服務(wù)端通過超媒體告訴客戶端當(dāng)前狀態(tài)有哪些后續(xù)狀態(tài)可以進(jìn)入。
這些類似"下一頁"之類的鏈接起的就是這種推進(jìn)狀態(tài)的作用——指引你如何從當(dāng)前狀態(tài)進(jìn)入下一個(gè)可能的狀態(tài)。
希望對大家理解restful api 有幫助。