1.什么是rest?
REST全稱是Representational State Transfer你虹,中文意思是表述(編者注:通常譯為表征)性狀態(tài)轉(zhuǎn)移构眯。 它首次出現(xiàn)在2000年Roy Fielding的博士論文中裆熙,Roy Fielding是HTTP規(guī)范的主要編寫者之一邓夕。 他在論文中提到:"我這篇文章的寫作目的掰茶,就是想在符合架構(gòu)原理的前提下萤厅,理解和評(píng)估以網(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上剃袍,只不過(guò)目前HTTP是唯一與REST相關(guān)的實(shí)例。 所以我們這里描述的REST也是通過(guò)HTTP實(shí)現(xiàn)的REST捎谨。
2.什么是RESTful
REST 指的是一組架構(gòu)約束條件和原則民效。滿足這些約束條件和原則的應(yīng)用程序或設(shè)計(jì)就是 RESTful憔维。
Web 應(yīng)用程序最重要的 REST 原則是,客戶端和服務(wù)器之間的交互在請(qǐng)求之間是無(wú)狀態(tài)的畏邢。從客戶端到服務(wù)器的每個(gè)請(qǐng)求都必須包含理解請(qǐng)求所必需的信息业扒。如果服務(wù)器在請(qǐng)求之間的任何時(shí)間點(diǎn)重啟,客戶端不會(huì)得到通知舒萎。此外程储,無(wú)狀態(tài)請(qǐng)求可以由任何可用服務(wù)器回答,這十分適合云計(jì)算之類的環(huán)境臂寝≌吕穑客戶端可以緩存數(shù)據(jù)以改進(jìn)性能。
在服務(wù)器端咆贬,應(yīng)用程序狀態(tài)和功能可以分為各種資源败徊。資源是一個(gè)有趣的概念實(shí)體,它向客戶端公開掏缎。資源的例子有:應(yīng)用程序?qū)ο笾灞摹?shù)據(jù)庫(kù)記錄、算法等等眷蜈。每個(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)的引擎,資源表示通過(guò)超鏈接互聯(lián)呆躲。
另一個(gè)重要的 REST 原則是分層系統(tǒng),這表示組件無(wú)法了解它與之交互的中間層以外的組件捶索。通過(guò)將系統(tǒng)知識(shí)限制在單個(gè)層弟孟,可以限制整個(gè)系統(tǒng)的復(fù)雜性别惦,促進(jìn)了底層的獨(dú)立性。
當(dāng) REST 架構(gòu)的約束條件作為一個(gè)整體應(yīng)用時(shí),將生成一個(gè)可以擴(kuò)展到大量客戶端的應(yīng)用程序绪励。它還降低了客戶端和服務(wù)器之間的交互延遲。統(tǒng)一界面簡(jiǎn)化了整個(gè)系統(tǒng)架構(gòu)址芯,改進(jìn)了子系統(tǒng)之間交互的可見性哥捕。REST 簡(jiǎn)化了客戶端和服務(wù)器的實(shí)現(xiàn)。
3.url(統(tǒng)一資源定位符)的設(shè)計(jì)
- 動(dòng)詞 + 賓語(yǔ)
RESTful 的核心思想就是构回,客戶端發(fā)出的數(shù)據(jù)操作指令都是"動(dòng)詞 + 賓語(yǔ)"的結(jié)構(gòu)夏块。比如疏咐,GET /articles這個(gè)命令,GET是動(dòng)詞脐供,/articles是賓語(yǔ)浑塞。
動(dòng)詞通常就是五種 HTTP 方法,對(duì)應(yīng) CRUD 操作政己。
GET:讀茸煤尽(Read)
POST:新建(Create)
PUT:更新(Update)
PATCH:更新(Update),通常是部分更新
DELETE:刪除(Delete)
根據(jù) HTTP 規(guī)范歇由,動(dòng)詞一律大寫卵牍。
- 動(dòng)詞的覆蓋
有些客戶端只能使用GET和POST這兩種方法。服務(wù)器必須接受POST模擬其他三個(gè)方法(PUT沦泌、PATCH糊昙、DELETE)。
這時(shí)赦肃,客戶端發(fā)出的 HTTP 請(qǐng)求溅蛉,要加上X-HTTP-Method-Override屬性,告訴服務(wù)器應(yīng)該使用哪一個(gè)動(dòng)詞他宛,覆蓋POST方法船侧。
POST /api/Person/4 HTTP/1.1
X-HTTP-Method-Override: PUT
上面代碼中,X-HTTP-Method-Override指定本次請(qǐng)求的方法是PUT厅各,而不是POST镜撩。
- 賓語(yǔ)必須是名詞
賓語(yǔ)就是 API 的 URL,是 HTTP 動(dòng)詞作用的對(duì)象队塘。它應(yīng)該是名詞袁梗,不能是動(dòng)詞。比如憔古,/articles這個(gè) URL 就是正確的遮怜,而下面的 URL 不是名詞,所以都是錯(cuò)誤的鸿市。
/getAllCars
/createNewCar
/deleteAllRedCars
- 復(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充岛。 - 避免多級(jí) URL
常見的情況是保檐,資源需要多級(jí)分類,因此很容易寫出多級(jí)的 URL裸准,比如獲取某個(gè)作者的某一類文章展东。
GET /authors/12/categories/2
RESTful的關(guān)鍵
RESTful的關(guān)鍵是定義可表示流程元素/資源的對(duì)象。在REST中炒俱,每一個(gè)對(duì)象都是通過(guò)URL來(lái)表示的盐肃,對(duì)象用戶負(fù)責(zé)將狀態(tài)信息打包進(jìn)每一條消息內(nèi),以便對(duì)象的處理總是無(wú)狀態(tài)的权悟。
4.狀態(tài)碼
4.1 狀態(tài)碼必須精確
客戶端的每一次請(qǐng)求砸王,服務(wù)器都必須給出回應(yīng)÷透螅回應(yīng)包括 HTTP 狀態(tài)碼和數(shù)據(jù)兩部分谦铃。
HTTP 狀態(tài)碼就是一個(gè)三位數(shù),分成五個(gè)類別榔昔。
1xx
:相關(guān)信息2xx
:操作成功3xx
:重定向4xx
:客戶端錯(cuò)誤5xx
:服務(wù)器錯(cuò)誤
每一種狀態(tài)碼都有標(biāo)準(zhǔn)的(或者約定的)解釋驹闰,客戶端只需查看狀態(tài)碼,就可以判斷出發(fā)生了什么情況撒会,所以服務(wù)器應(yīng)該返回盡可能精確的狀態(tài)碼嘹朗。
API 不需要1xx
狀態(tài)碼,下面介紹其他四類狀態(tài)碼的精確含義诵肛。
4.2 2xx 狀態(tài)碼
200
狀態(tài)碼表示操作成功屹培,但是不同的方法可以返回更精確的狀態(tài)碼。
- GET: 200 OK
- POST: 201 Created
- PUT: 200 OK
- PATCH: 200 OK
- DELETE: 204 No Content
上面代碼中怔檩,POST
返回201
狀態(tài)碼褪秀,表示生成了新的資源;DELETE
返回204
狀態(tài)碼薛训,表示資源已經(jīng)不存在媒吗。
此外,202 Accepted
狀態(tài)碼表示服務(wù)器已經(jīng)收到請(qǐng)求乙埃,但還未進(jìn)行處理闸英,會(huì)在未來(lái)再處理,通常用于異步操作膊爪。下面是一個(gè)例子。
HTTP/1.1 202 Accepted
{
"task": {
"href": "/api/company/job-management/jobs/2130040",
"id": "2130040"
}
}
4.3 3xx 狀態(tài)碼
API 用不到301
狀態(tài)碼(永久重定向)和302
狀態(tài)碼(暫時(shí)重定向嚎莉,307
也是這個(gè)含義)米酬,因?yàn)樗鼈兛梢杂蓱?yīng)用級(jí)別返回,瀏覽器會(huì)直接跳轉(zhuǎn)趋箩,API 級(jí)別可以不考慮這兩種情況赃额。
API 用到的3xx
狀態(tài)碼加派,主要是303 See Other
,表示參考另一個(gè) URL跳芳。它與302
和307
的含義一樣芍锦,也是"暫時(shí)重定向",區(qū)別在于302
和307
用于GET
請(qǐng)求飞盆,而303
用于POST
娄琉、PUT
和DELETE
請(qǐng)求。收到303
以后吓歇,瀏覽器不會(huì)自動(dòng)跳轉(zhuǎn)孽水,而會(huì)讓用戶自己決定下一步怎么辦。下面是一個(gè)例子城看。
HTTP/1.1 303 See Other
Location: /api/orders/12345
4.4 4xx 狀態(tài)碼
4xx
狀態(tài)碼表示客戶端錯(cuò)誤女气,主要有下面幾種。
400 Bad Request
:服務(wù)器不理解客戶端的請(qǐng)求测柠,未做任何處理炼鞠。
401 Unauthorized
:用戶未提供身份驗(yàn)證憑據(jù),或者沒有通過(guò)身份驗(yàn)證轰胁。
403 Forbidden
:用戶通過(guò)了身份驗(yàn)證谒主,但是不具有訪問(wèn)資源所需的權(quán)限。
404 Not Found
:所請(qǐng)求的資源不存在软吐,或不可用瘩将。
405 Method Not Allowed
:用戶已經(jīng)通過(guò)身份驗(yàn)證,但是所用的 HTTP 方法不在他的權(quán)限之內(nèi)凹耙。
410 Gone
:所請(qǐng)求的資源已從這個(gè)地址轉(zhuǎn)移姿现,不再可用。
415 Unsupported Media Type
:客戶端要求的返回格式不支持肖抱。比如备典,API 只能返回 JSON 格式,但是客戶端要求返回 XML 格式意述。
422 Unprocessable Entity
:客戶端上傳的附件無(wú)法處理提佣,導(dǎo)致請(qǐng)求失敗。
429 Too Many Requests
:客戶端的請(qǐng)求次數(shù)超過(guò)限額荤崇。
4.5 5xx 狀態(tài)碼
5xx
狀態(tài)碼表示服務(wù)端錯(cuò)誤拌屏。一般來(lái)說(shuō),API 不會(huì)向用戶透露服務(wù)器的詳細(xì)信息术荤,所以只要兩個(gè)狀態(tài)碼就夠了倚喂。
500 Internal Server Error
:客戶端請(qǐng)求有效,服務(wù)器處理時(shí)發(fā)生了意外瓣戚。
503 Service Unavailable
:服務(wù)器無(wú)法處理請(qǐng)求端圈,一般用于網(wǎng)站維護(hù)狀態(tài)焦读。
5.服務(wù)器回應(yīng)
5.1 不要返回純本文
API 返回的數(shù)據(jù)格式,不應(yīng)該是純文本舱权,而應(yīng)該是一個(gè) JSON 對(duì)象矗晃,因?yàn)檫@樣才能返回標(biāo)準(zhǔn)的結(jié)構(gòu)化數(shù)據(jù)。所以宴倍,服務(wù)器回應(yīng)的 HTTP 頭的Content-Type
屬性要設(shè)為application/json
张症。
客戶端請(qǐng)求時(shí),也要明確告訴服務(wù)器啊楚,可以接受 JSON 格式吠冤,即請(qǐng)求的 HTTP 頭的ACCEPT
屬性也要設(shè)成application/json
。下面是一個(gè)例子恭理。
GET /orders/2 HTTP/1.1
Accept: application/json
5.2 發(fā)生錯(cuò)誤時(shí)拯辙,不要返回 200 狀態(tài)碼
有一種不恰當(dāng)?shù)淖龇ㄊ牵词拱l(fā)生錯(cuò)誤颜价,也返回200
狀態(tài)碼涯保,把錯(cuò)誤信息放在數(shù)據(jù)體里面,就像下面這樣周伦。
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "failure",
"data": {
"error": "Expected at least two items in list."
}
}
上面代碼中夕春,解析數(shù)據(jù)體以后,才能得知操作失敗专挪。
這張做法實(shí)際上取消了狀態(tài)碼及志,這是完全不可取的。正確的做法是寨腔,狀態(tài)碼反映發(fā)生的錯(cuò)誤速侈,具體的錯(cuò)誤信息放在數(shù)據(jù)體里面返回。下面是一個(gè)例子迫卢。
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Invalid payoad.",
"detail": {
"surname": "This field is required."
}
}
5.3 提供鏈接
在回應(yīng)中倚搬,給出相關(guān)鏈接,便于下一步操作乾蛤。這樣的話每界,用戶只要記住一個(gè) URL,就可以發(fā)現(xiàn)其他的 URL家卖。這種方法叫做 HATEOAS眨层。