淺談Restful Api的知識

前言: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 有幫助。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容