淺談Restful Api的知識(shí)

前言:restful出現(xiàn)的環(huán)境,什么是rest?以及出現(xiàn)的意義

1.REST的由來(lái)

全稱: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ī)范的主要編寫(xiě)者之一。 他在論文中提到:"我這篇文章的寫(xiě)作目的,就是想在符合架構(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本身并沒(méi)有創(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。

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í)體,它向客戶端公開(kāi)。資源的例子有:應(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ú)立性

REST 描述了一個(gè)架構(gòu)樣式的互聯(lián)系統(tǒng)(如 Web 應(yīng)用程序)。REST 約束條件作為一個(gè)整體應(yīng)用時(shí),將生成一個(gè)簡(jiǎn)單、可擴(kuò)展、有效、安全、可靠的架構(gòu)。由于它簡(jiǎn)便、輕量級(jí)以及通過(guò) HTTP 直接傳輸數(shù)據(jù)的特性,RESTful Web 服務(wù)成為基于 SOAP 服務(wù)的一個(gè)最有前途的替代方案。用于 web 服務(wù)和動(dòng)態(tài) Web 應(yīng)用程序的多層架構(gòu)可以實(shí)現(xiàn)可重用性、簡(jiǎn)單性、可擴(kuò)展性和組件可響應(yīng)性的清晰分離。開(kāi)發(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

定義:簡(jiǎn)單來(lái)說(shuō)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)變化。通過(guò)HTTP動(dòng)詞實(shí)現(xiàn)。

背景:早期的網(wǎng)頁(yè)端是前后臺(tái)一起的,比如PHP、JSP等。而隨著近幾年移動(dòng)端的快速發(fā)展和分布式架構(gòu)的應(yīng)用,各種Client層出不窮,這個(gè)時(shí)候就需要有個(gè)統(tǒng)一的機(jī)制,來(lái)為前后端通信提供服務(wù)。

? ? ?而RESTful API就是目前比較成熟的的一套應(yīng)用程序API設(shè)計(jì)理論。

目的:Client和Server端進(jìn)一步解耦。

應(yīng)用:最為經(jīng)典的莫過(guò)于github API。

2.什么是服務(wù)?

任何業(yè)務(wù)服務(wù)都可以抽象為對(duì)象的狀態(tài)維護(hù),基本操作就増刪查改四種.

例如:

訪問(wèn)文章的,很明顯就是對(duì)文章及其列表的增刪查改,文章是被做操的對(duì)象,通過(guò)增刪查改修改文章的狀態(tài).

銀行轉(zhuǎn)賬,好像是有邏輯行為,但實(shí)際上每個(gè)轉(zhuǎn)賬事務(wù),可以理解為對(duì)一個(gè)賬單對(duì)象的狀態(tài)操作,這個(gè)賬單又關(guān)聯(lián)了多個(gè)賬戶的狀態(tài).

現(xiàn)實(shí)生活中一個(gè)人走路,是一個(gè)明顯的對(duì)象行為,也可以表示為人這個(gè)對(duì)象從位置A經(jīng)過(guò)時(shí)間T后變?yōu)槲恢肂的狀態(tài)更新操作.

服務(wù)端無(wú)論使用何種架構(gòu),加入緩存,隊(duì)列,數(shù)據(jù)庫(kù),最終的目標(biāo)就是維護(hù)資源的狀態(tài).

從客戶端的視角來(lái)看,服務(wù)端API描述的內(nèi)容就是其維護(hù)的對(duì)象的瞬時(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ì)的軟件可以更簡(jiǎn)潔,更有層次,更易于實(shí)現(xiàn)緩存等機(jī)制。

RESTful架構(gòu),就是目前最流行的一種互聯(lián)網(wǎng)軟件架構(gòu)。它結(jié)構(gòu)清晰、符合標(biāo)準(zhǔn)、易于理解、擴(kuò)展方便,所以正得到越來(lái)越多網(wǎng)站的采用。

RESTful?是目前最流行的 API 設(shè)計(jì)規(guī)范,用于 Web 數(shù)據(jù)接口的設(shè)計(jì)。傳統(tǒng)上,軟件和網(wǎng)絡(luò)是兩個(gè)不同的領(lǐng)域,很少有交集;軟件開(kāi)發(fā)主要針對(duì)單機(jī)環(huán)境,網(wǎng)絡(luò)則主要研究系統(tǒng)之間的通信。在當(dāng)今的互聯(lián)網(wǎng)應(yīng)用的前端展示媒介很豐富。有手機(jī)、有平板電腦還有PC以及其他的展示媒介。那么這些前端接收到的用戶請(qǐng)求統(tǒng)一由一個(gè)后臺(tái)來(lái)處理并返回給不同的前端肯定是最科學(xué)和最經(jīng)濟(jì)的方式,RESTful API就是一套協(xié)議來(lái)規(guī)范多種形式的前端和同一個(gè)后臺(tái)的交互方式.

一.資源與URI

二.統(tǒng)一資源接口

三.資源的表述

四.資源的鏈接

五.狀態(tài)的轉(zhuǎn)移

(1).為什么是RESTful

服務(wù)端面向Web的API需要通過(guò)HTTP協(xié)議來(lái)表達(dá).了解一下REST的起源可以知道其作者是HTTP協(xié)議的制定者,所以HTTP協(xié)議的語(yǔ)義元素天然符合REST的約束要求.但RESTful并不是強(qiáng)制的,Web API不必遵循RESTful,但是遵循RESTful可以令A(yù)PI表達(dá)的語(yǔ)義更簡(jiǎn)單清晰統(tǒng)一,在語(yǔ)義全部抽象為轉(zhuǎn)臺(tái)轉(zhuǎn)移后,分布式系統(tǒng)的架構(gòu)關(guān)注點(diǎn)(維護(hù)狀態(tài)一致)也會(huì)更明確.前后端分離主要是以API為界限進(jìn)行解耦的,這就會(huì)產(chǎn)生大量的API,采用RESTful來(lái)設(shè)計(jì)API主要有以下好處:

一、表現(xiàn)力更強(qiáng),更易于理解

二、RESRful是無(wú)狀態(tài),所以不管前端是何種設(shè)備何種狀態(tài)都可以無(wú)差別的請(qǐng)求資源

(2).RESTful的初級(jí)內(nèi)容

一.使用METHOD (POST,DELETE,GET,PUT) 等動(dòng)詞表示増刪查改四種操作.

二.使用URI(通常是其子集URL)來(lái)表示對(duì)象或資源.

三.使用queryString表示查詢輸入

四.使用body表示更新和保存的狀態(tài)輸入

五.使用HEAD進(jìn)行擴(kuò)展

(3).怎么用RESTful

一、每個(gè)資源使用2個(gè)URL,網(wǎng)址中只能有名詞

二、對(duì)于資源的操作類型由HTTP動(dòng)詞來(lái)表示

三、統(tǒng)一的返回結(jié)果

四、返回正確的狀態(tài)碼

五、允許通過(guò)HTTP內(nèi)容協(xié)商,建議格式預(yù)定義為JSON

六、對(duì)可選發(fā)雜的參數(shù),使用查詢字符串(?)

七、返回有用的錯(cuò)誤信息(message)

八、非資源請(qǐng)求用動(dòng)詞,這看起似乎和1中的說(shuō)法有矛盾,但這里指的是非資源,而不是資源

(4).RESTful架構(gòu)優(yōu)點(diǎn):

一.前后端分離,減少流量

二.安全問(wèn)題集中在接口上,由于接受json格式,防止了注入型等安全問(wèn)題

三.前端無(wú)關(guān)化,后端只負(fù)責(zé)數(shù)據(jù)處理,前端表現(xiàn)方式可以是任何前端語(yǔ)言(android,ios,html5)

四.前端和后端人員更加專注于各自開(kāi)發(fā),只需接口文檔便可完成前后端交互,無(wú)需過(guò)多相互了解

五.服務(wù)器性能優(yōu)化:由于前端是靜態(tài)頁(yè)面,通過(guò)nginx便可獲取,服務(wù)器主要壓力放在了接口上

4.RESTful api 規(guī)范以及設(shè)計(jì)原則

(1)URL 設(shè)計(jì)(資源與URI)

REST全稱是表述性狀態(tài)轉(zhuǎn)移,那究竟指的是什么的表述? 其實(shí)指的就是資源。任何事物,只要有被引用到的必要,它就是一個(gè)資源。資源可以是實(shí)體(例如手機(jī)號(hào)碼),也可以只是一個(gè)抽象概念(例如價(jià)值) 。下面是一些資源的例子:

某用戶的手機(jī)號(hào)碼

某用戶的個(gè)人信息

最多用戶訂購(gòu)的GPRS套餐

兩個(gè)產(chǎn)品之間的依賴關(guān)系

某用戶可以辦理的優(yōu)惠套餐

某手機(jī)號(hào)碼的潛在價(jià)值

要讓一個(gè)資源可以被識(shí)別,需要有個(gè)唯一標(biāo)識(shí),在Web中這個(gè)唯一標(biāo)識(shí)就是URI(Uniform Resource Identifier)。

URI既可以看成是資源的地址,也可以看成是資源的名稱。如果某些信息沒(méi)有使用URI來(lái)表示,那它就不能算是一個(gè)資源, 只能算是資源的一些信息而已。URI的設(shè)計(jì)應(yīng)該遵循可尋址性原則,具有自描述性,需要在形式上給人以直覺(jué)上的關(guān)聯(lián)。

一.? ? 使用_或-來(lái)讓URI可讀性更好

二.? ? 使用/來(lái)表示資源的層級(jí)關(guān)系

三.? ? ?使用?用來(lái)過(guò)濾資源

四.? ? ,或;可以用來(lái)表示同級(jí)資源的關(guān)系

1.1 動(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 操作。

根據(jù) HTTP 規(guī)范,動(dòng)詞一律大寫(xiě)。

1.2 動(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方法。


上面代碼中,X-HTTP-Method-Override指定本次請(qǐng)求的方法是PUT,而不是POST。

1.3 賓語(yǔ)必須是名詞

賓語(yǔ)就是 API 的 URL,是 HTTP 動(dòng)詞作用的對(duì)象。它應(yīng)該是名詞,不能是動(dòng)詞。比如,/articles這個(gè) URL 就是正確的,而下面的 URL 不是名詞,所以都是錯(cuò)誤的。



1.4 復(fù)數(shù) URL

既然 URL 是名詞,那么應(yīng)該使用復(fù)數(shù),還是單數(shù)?

這沒(méi)有統(tǒng)一的規(guī)定,但是常見(jiàn)的操作是讀取一個(gè)集合,比如GET /articles(讀取所有文章),這里明顯應(yīng)該是復(fù)數(shù)。

為了統(tǒng)一起見(jiàn),建議都使用復(fù)數(shù) URL,比如GET /articles/2要好于GET /article/2。

1.5 避免多級(jí) URL

常見(jiàn)的情況是,資源需要多級(jí)分類,因此很容易寫(xiě)出多級(jí)的 URL,比如獲取某個(gè)作者的某一類文章。

GET /authors/12/categories/2

這種 URL 不利于擴(kuò)展,語(yǔ)義也不明確,往往要想一會(huì),才能明白含義。

更好的做法是,除了第一級(jí),其他級(jí)別都用查詢字符串表達(dá)。

GET /authors/12?categories=2

下面是另一個(gè)例子,查詢已發(fā)布的文章。你可能會(huì)設(shè)計(jì)成下面的 URL。

GET /articles/published

查詢字符串的寫(xiě)法明顯更好。

GET /articles?published=true

?(2)統(tǒng)一資源接口(狀態(tài)碼)

RESTful風(fēng)格的數(shù)據(jù)元操CRUD(create,read,update,delete)分別對(duì)應(yīng)HTTP方法:GET用來(lái)獲取資源,POST用來(lái)新建資源(也可以用于更新資源),PUT用來(lái)更新資源,DELETE用來(lái)刪除資源,這樣就統(tǒng)一了數(shù)據(jù)操作的接口。

RESTful架構(gòu)應(yīng)該遵循統(tǒng)一接口原則(如上),統(tǒng)一接口包含了一組受限的預(yù)定義的操作,不論什么樣的資源,都是通過(guò)使用相同的接口進(jìn)行資源的訪問(wèn)。接口應(yīng)該使用標(biāo)準(zhǔn)的HTTP方法如GET,PUT和POST,并遵循這些方法的語(yǔ)義。

果按照HTTP方法的語(yǔ)義來(lái)暴露資源,那么接口將會(huì)擁有安全性和冪等性的特性,例如GET和HEAD請(qǐng)求都是安全的, 無(wú)論請(qǐng)求多少次,都不會(huì)改變服務(wù)器狀態(tài)。而GET、HEAD、PUT和DELETE請(qǐng)求都是冪等的,無(wú)論對(duì)資源操作多少次, 結(jié)果總是一樣的,后面的請(qǐng)求并不會(huì)產(chǎn)生比第一次更多的影響。

一.下面列出了GET,DELETE,PUT和POST的典型用法:

1.GET

安全且冪等

獲取表示

變更時(shí)獲取表示(緩存)

200(OK) - 表示已在響應(yīng)中發(fā)出

204(無(wú)內(nèi)容) - 資源有空表示

301(Moved Permanently) - 資源的URI已被更新

303(See Other) - 其他(如,負(fù)載均衡)

304(not modified)- 資源未更改(緩存)

400 (bad request)- 指代壞請(qǐng)求(如,參數(shù)錯(cuò)誤)

404 (not found)- 資源不存在

406 (not acceptable)- 服務(wù)端不支持所需表示

500 (internal server error)- 通用錯(cuò)誤響應(yīng)

503 (Service Unavailable)- 服務(wù)端當(dāng)前無(wú)法處理請(qǐng)求

2.POST

不安全且不冪等

使用服務(wù)端管理的(自動(dòng)產(chǎn)生)的實(shí)例號(hào)創(chuàng)建資源

創(chuàng)建子資源

部分更新資源

如果沒(méi)有被修改,則不過(guò)更新資源(樂(lè)觀鎖)

200(OK)- 如果現(xiàn)有資源已被更改

201(created)- 如果新資源被創(chuàng)建

202(accepted)- 已接受處理請(qǐng)求但尚未完成(異步處理)

301(Moved Permanently)- 資源的URI被更新

303(See Other)- 其他(如,負(fù)載均衡)

400(bad request)- 指代壞請(qǐng)求

404 (not found)- 資源不存在

406 (not acceptable)- 服務(wù)端不支持所需表示

409 (conflict)- 通用沖突

412 (Precondition Failed)- 前置條件失敗(如執(zhí)行條件更新時(shí)的沖突)

415 (unsupported media type)- 接受到的表示不受支持

500 (internal server error)- 通用錯(cuò)誤響應(yīng)

503 (Service Unavailable)- 服務(wù)當(dāng)前無(wú)法處理請(qǐng)求

3.PUT

不安全但冪等

用客戶端管理的實(shí)例號(hào)創(chuàng)建一個(gè)資源

通過(guò)替換的方式更新資源

如果未被修改,則更新資源(樂(lè)觀鎖)

200 (OK)- 如果已存在資源被更改

201 (created)- 如果新資源被創(chuàng)建

301(Moved Permanently)- 資源的URI已更改

303 (See Other)- 其他(如,負(fù)載均衡)

400 (bad request)- 指代壞請(qǐng)求

404 (not found)- 資源不存在

406 (not acceptable)- 服務(wù)端不支持所需表示

409 (conflict)- 通用沖突

412 (Precondition Failed)- 前置條件失敗(如執(zhí)行條件更新時(shí)的沖突)

415 (unsupported media type)- 接受到的表示不受支持

500 (internal server error)- 通用錯(cuò)誤響應(yīng)

503 (Service Unavailable)- 服務(wù)當(dāng)前無(wú)法處理請(qǐng)求

4.DELETE

不安全但冪等

刪除資源

200 (OK)- 資源已被刪除

301 (Moved Permanently)- 資源的URI已更改

303 (See Other)- 其他,如負(fù)載均衡

400 (bad request)- 指代壞請(qǐng)求

404 (not found)- 資源不存在

409 (conflict)- 通用沖突

500 (internal server error)- 通用錯(cuò)誤響應(yīng)

503 (Service Unavailable)- 服務(wù)端當(dāng)前無(wú)法處理請(qǐng)求

2.HTTP 狀態(tài)碼就是一個(gè)三位數(shù),分成五個(gè)類別。

1.? ? 1xx:相關(guān)信息

2.? ? ?2xx:操作成功

3.? ? ?3xx:重定向

4.? ? ?4xx:客戶端錯(cuò)誤

5.? ? ?5xx:服務(wù)器錯(cuò)誤

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)用級(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ì)讓用戶自己決定下一步怎么辦。

2.3? ? ? ?4xx 狀態(tài)碼

4xx狀態(tài)碼表示客戶端錯(cuò)誤,主要有下面幾種。

400 Bad Request:服務(wù)器不理解客戶端的請(qǐng)求,未做任何處理。

401 Unauthorized:用戶未提供身份驗(yàn)證憑據(jù),或者沒(méi)有通過(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ò)限額。

2.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)。

2.6? ? 下面我們來(lái)看一些實(shí)踐中常見(jiàn)的問(wèn)題:

POST和PUT用于創(chuàng)建資源時(shí)有什么區(qū)別?

POST和PUT在創(chuàng)建資源的區(qū)別在于,所創(chuàng)建的資源的名稱(URI)是否由客戶端決定。 例如為我的博文增加一個(gè)java的分類,生成的路徑就是分類名/categories/java,那么就可以采用PUT方法。不過(guò)很多人直接把POST、GET、PUT、DELETE直接對(duì)應(yīng)上CRUD,例如在一個(gè)典型的rails實(shí)現(xiàn)的RESTful應(yīng)用中就是這么做的。

我認(rèn)為,這是因?yàn)閞ails默認(rèn)使用服務(wù)端生成的ID作為URI的緣故,而不少人就是通過(guò)rails實(shí)踐REST的,所以很容易造成這種誤解。

客戶端不一定都支持這些HTTP方法吧?

的確有這種情況,特別是一些比較古老的基于瀏覽器的客戶端,只能支持GET和POST兩種方法。

在實(shí)踐上,客戶端和服務(wù)端都可能需要做一些妥協(xié)。例如rails框架就支持通過(guò)隱藏參數(shù)_method=DELETE來(lái)傳遞真實(shí)的請(qǐng)求方法, 而像Backbone這樣的客戶端MVC框架則允許傳遞_method傳輸和設(shè)置X-HTTP-Method-Override頭來(lái)規(guī)避這個(gè)問(wèn)題。

統(tǒng)一接口是否意味著不能擴(kuò)展帶特殊語(yǔ)義的方法?

統(tǒng)一接口并不阻止你擴(kuò)展方法,只要方法對(duì)資源的操作有著具體的、可識(shí)別的語(yǔ)義即可,并能夠保持整個(gè)接口的統(tǒng)一性。

像WebDAV就對(duì)HTTP方法進(jìn)行了擴(kuò)展,增加了LOCK、UPLOCK等方法。而github的API則支持使用PATCH方法來(lái)進(jìn)行issue的更新

(3)服務(wù)器回應(yīng)(資源的表述)

3.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客戶端通過(guò)HTTP方法可以獲取資源,是吧? 不,確切的說(shuō),客戶端獲取的只是資源的表述而已。 資源在外界的具體呈現(xiàn),可以有多種表述(或成為表現(xiàn)、表示)形式,在客戶端和服務(wù)端之間傳送的也是資源的表述,而不是資源本身。 例如文本資源可以采用html、xml、json等格式,圖片可以使用PNG或JPG展現(xiàn)出來(lái)。

資源的表述包括數(shù)據(jù)和描述數(shù)據(jù)的元數(shù)據(jù),例如,HTTP頭"Content-Type" 就是這樣一個(gè)元數(shù)據(jù)屬性。

那么客戶端如何知道服務(wù)端提供哪種表述形式呢?

答案是可以通過(guò)HTTP內(nèi)容協(xié)商,客戶端可以通過(guò)Accept頭請(qǐng)求一種特定格式的表述,服務(wù)端則通過(guò)Content-Type告訴客戶端資源的表述形式。



使用URI后綴來(lái)區(qū)分表述格式

像rails框架,就支持使用/users.xml或/users.json來(lái)區(qū)分不同的格式。 這樣的方式對(duì)于客戶端來(lái)說(shuō),無(wú)疑是更為直觀,但混淆了資源的名稱和資源的表述形式。 我個(gè)人認(rèn)為,還是應(yīng)該優(yōu)先使用內(nèi)容協(xié)商來(lái)區(qū)分表述格式。

3.2 發(fā)生錯(cuò)誤時(shí),不要返回 200 狀態(tài)碼

有一種不恰當(dāng)?shù)淖龇ㄊ牵词拱l(fā)生錯(cuò)誤,也返回200狀態(tài)碼,把錯(cuò)誤信息放在數(shù)據(jù)體里面,就像下面這樣。

上面代碼中,解析數(shù)據(jù)體以后,才能得知操作失敗。

這張做法實(shí)際上取消了狀態(tài)碼,這是完全不可取的。正確的做法是,狀態(tài)碼反映發(fā)生的錯(cuò)誤,具體的錯(cuò)誤信息放在數(shù)據(jù)體里面返回。下面是一個(gè)例子。


3.3 提供鏈接

API 的使用者未必知道,URL 是怎么設(shè)計(jì)的。一個(gè)解決方法就是,在回應(yīng)中,給出相關(guān)鏈接,便于下一步操作。這樣的話,用戶只要記住一個(gè) URL,就可以發(fā)現(xiàn)其他的 URL。這種方法叫做 HATEOAS。

舉例來(lái)說(shuō),GitHub 的 API 都在?api.github.com?這個(gè)域名。訪問(wèn)它,就可以得到其他 URL。


上面的回應(yīng)中,挑一個(gè) URL 訪問(wèn),又可以得到別的 URL。對(duì)于用戶來(lái)說(shuō),不需要記住 URL 設(shè)計(jì),只要從 api.github.com 一步步查找就可以了。

HATEOAS 的格式?jīng)]有統(tǒng)一規(guī)定,上面例子中,GitHub 將它們與其他屬性放在一起。更好的做法應(yīng)該是,將相關(guān)鏈接與其他屬性分開(kāi)。



?4 資源的鏈接

我們知道REST是使用標(biāo)準(zhǔn)的HTTP方法來(lái)操作資源的,但僅僅因此就理解成帶CURD的Web數(shù)據(jù)庫(kù)架構(gòu)就太過(guò)于簡(jiǎn)單了。

這種反模式忽略了一個(gè)核心概念:"超媒體即應(yīng)用狀態(tài)引擎(hypermedia as the engine of application state)"。 超媒體是什么?

當(dāng)你瀏覽Web網(wǎng)頁(yè)時(shí),從一個(gè)連接跳到一個(gè)頁(yè)面,再?gòu)牧硪粋€(gè)連接跳到另外一個(gè)頁(yè)面,就是利用了超媒體的概念:把一個(gè)個(gè)把資源鏈接起來(lái).

要達(dá)到這個(gè)目的,就要求在表述格式里邊加入鏈接來(lái)引導(dǎo)客戶端。在《RESTful Web Services》一書(shū)中,作者把這種具有鏈接的特性成為連通性。下面我們具體來(lái)看一些例子。

下面展示的是github獲取某個(gè)組織下的項(xiàng)目列表的請(qǐng)求,可以看到在響應(yīng)頭里邊增加Link頭告訴客戶端怎么訪問(wèn)下一頁(yè)和最后一頁(yè)的記錄。 而在響應(yīng)體里邊,用url來(lái)鏈接項(xiàng)目所有者和項(xiàng)目地址。


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



上面的例子展示了如何使用超媒體來(lái)增強(qiáng)資源的連通性。很多人在設(shè)計(jì)RESTful架構(gòu)時(shí),使用很多時(shí)間來(lái)尋找漂亮的URI,而忽略了超媒體。所以,應(yīng)該多花一些時(shí)間來(lái)給資源的表述提供鏈接,而不是專注于"資源的CRUD"。

4.1狀態(tài)的轉(zhuǎn)移

有了上面的鋪墊,再討論REST里邊的狀態(tài)轉(zhuǎn)移就會(huì)很容易理解了。

不過(guò),我們先來(lái)討論一下REST原則中的無(wú)狀態(tài)通信原則。初看一下,好像自相矛盾了,既然無(wú)狀態(tài),何來(lái)狀態(tài)轉(zhuǎn)移一說(shuō)?

其實(shí),這里說(shuō)的無(wú)狀態(tài)通信原則,并不是說(shuō)客戶端應(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ù)端的交互必須是無(wú)狀態(tài)的,并在每一次請(qǐng)求中包含處理該請(qǐng)求所需的一切信息。

服務(wù)端不需要在請(qǐng)求間保留應(yīng)用狀態(tài),只有在接受到實(shí)際請(qǐng)求的時(shí)候,服務(wù)端才會(huì)關(guān)注應(yīng)用狀態(tài)。

這種無(wú)狀態(tài)通信原則,使得服務(wù)端和中介能夠理解獨(dú)立的請(qǐng)求和響應(yīng)。

在多次請(qǐng)求中,同一客戶端也不再需要依賴于同一服務(wù)器,方便實(shí)現(xiàn)高可擴(kuò)展和高可用性的服務(wù)端。

但有時(shí)候我們會(huì)做出違反無(wú)狀態(tài)通信原則的設(shè)計(jì),例如利用Cookie跟蹤某個(gè)服務(wù)端會(huì)話狀態(tài),常見(jiàn)的像J2EE里邊的JSESSIONID。

這意味著,瀏覽器隨各次請(qǐng)求發(fā)出去的Cookie是被用于構(gòu)建會(huì)話狀態(tài)的。

當(dāng)然,如果Cookie保存的是一些服務(wù)器不依賴于會(huì)話狀態(tài)即可驗(yàn)證的信息(比如認(rèn)證令牌),這樣的Cookie也是符合REST原則的。

4.1.2 應(yīng)用狀態(tài)的轉(zhuǎn)移

狀態(tài)轉(zhuǎn)移到這里已經(jīng)很好理解了, "會(huì)話"狀態(tài)不是作為資源狀態(tài)保存在服務(wù)端的,而是被客戶端作為應(yīng)用狀態(tài)進(jìn)行跟蹤的。客戶端應(yīng)用狀態(tài)在服務(wù)端提供的超媒體的指引下發(fā)生變遷。服務(wù)端通過(guò)超媒體告訴客戶端當(dāng)前狀態(tài)有哪些后續(xù)狀態(tài)可以進(jìn)入。

這些類似"下一頁(yè)"之類的鏈接起的就是這種推進(jìn)狀態(tài)的作用——指引你如何從當(dāng)前狀態(tài)進(jìn)入下一個(gè)可能的狀態(tài)。

希望對(duì)大家理解restful api 有幫助。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容