從今天開(kāi)始,我開(kāi)始學(xué)習(xí)Retrofit,整體Retrofit內(nèi)容如下:
好的,那開(kāi)始今天的內(nèi)容
隨著Google對(duì)HttpClient的摒棄,和Volley的逐漸沒(méi)落,OkHttp開(kāi)始異軍突起,Retrofit對(duì)OkHttp進(jìn)行了強(qiáng)制依賴。Retrofit是由Square公司出品的針對(duì)于Android和Java的類型安全的Http客戶端,如果看源碼會(huì)發(fā)現(xiàn)其實(shí)本質(zhì)上是OkHttp的封裝,使用面向接口的方式進(jìn)行網(wǎng)絡(luò)請(qǐng)求,利用動(dòng)態(tài)生成的代理類封裝了網(wǎng)絡(luò)接口請(qǐng)求的底層,其將請(qǐng)求返回JavaBean,對(duì)網(wǎng)絡(luò)認(rèn)證REST API進(jìn)行了很友好的支持。使用Retrofit將會(huì)極大的提高我們應(yīng)用的網(wǎng)絡(luò)體驗(yàn)。
本篇文章是Retrofit的前哨站——理解RESTful。因?yàn)閞etrofit是基于RESTful架構(gòu)。所以在講解Retrofit之前,先來(lái)復(fù)習(xí)一下RESTful。本篇文章內(nèi)容如下:
- 1.RESTful的前世今生
- 2.RESTful的理解
- 3.RESTful的原則
- 4.RESTful、RPC、SOAP的愛(ài)恨情仇
- 5.總結(jié)
在移動(dòng)互聯(lián)網(wǎng)的大潮下,前后端分離的場(chǎng)景下,隨著docker等技術(shù)的興起,“微服務(wù)”的概念越來(lái)越被大家接受的的情況下,RESTful API成為越來(lái)越重要的移動(dòng)端和服務(wù)器的交互形式。尤其在很多互聯(lián)公司或者傳統(tǒng)公司轉(zhuǎn)型擁抱互聯(lián)網(wǎng)的公司,一套設(shè)計(jì)良好的RESTful API能夠幫助互聯(lián)網(wǎng)產(chǎn)品支持單個(gè)服務(wù)端+多個(gè)客戶端的場(chǎng)景。RESTful架構(gòu)本身是一個(gè)風(fēng)格而不是一個(gè)標(biāo)準(zhǔn),本文將圍繞RESTful架構(gòu)展開(kāi)討論,歡迎大家拍磚。
RESTful架構(gòu),就是目前最流行的一種互聯(lián)網(wǎng)軟件架構(gòu)。它結(jié)構(gòu)清晰、符合標(biāo)準(zhǔn)、易于理解、方便擴(kuò)展,所以得到越來(lái)越多的應(yīng)用。
但是,RESTful到底是什么?并不是一個(gè)容易說(shuō)清楚的問(wèn)題。那么我們先來(lái)了解下RESTful的前世今生。
一、RESTful的前世今生
、RESTful之父---Roy Fielding
在介紹RESTful之前需要介紹一下Roy Fielding。RESTful這個(gè)單詞因?yàn)槭窃?000年的他的博士論文中首次出現(xiàn)的。
Roy Fielding是一個(gè)非常重要的人,他是HTTP協(xié)議(1.0/1.1)的主要設(shè)計(jì)者、Apache服務(wù)器軟件的作者之一,Apache基金會(huì)的第一任主席。所以他的這篇論文已經(jīng)發(fā)布,就引起了關(guān)注,并且立即對(duì)互聯(lián)網(wǎng)產(chǎn)生了深遠(yuǎn)的影響。
他這樣介紹論文的寫作目的:
"本文研究計(jì)算機(jī)科學(xué)兩大前沿----軟件和網(wǎng)絡(luò)----的交叉點(diǎn)。長(zhǎng)期以來(lái),軟件研究主要關(guān)注軟件設(shè)計(jì)的分類、設(shè)計(jì)方法的演化,很少客觀地評(píng)估不同的設(shè)計(jì)選擇對(duì)系統(tǒng)行為的影響。而相反地,網(wǎng)絡(luò)研究主要關(guān)注系統(tǒng)之間通信行為的細(xì)節(jié)、如何改進(jìn)特定通信機(jī)制的表現(xiàn),常常忽視了一個(gè)事實(shí),那就是改變應(yīng)用程序的互動(dòng)風(fēng)格比改變互動(dòng)協(xié)議,對(duì)整體表現(xiàn)有更大的影響。我這篇文章的寫作目的,就是想在符合架構(gòu)原理的前提下,理解和評(píng)估以網(wǎng)絡(luò)為基礎(chǔ)的應(yīng)用軟件的架構(gòu)設(shè)計(jì),得到一個(gè)功能強(qiáng)、性能好、適宜通信的架構(gòu)。"
(This dissertation explores a junction on the frontiers of two research disciplines in computer science: software and networking. Software research has long been concerned with the categorization of software designs and the development of design methodologies, but has rarely been able to objectively evaluate the impact of various design choices on system behavior. Networking research, in contrast, is focused on the details of generic communication behavior between systems and improving the performance of particular communication techniques, often ignoring the fact that changing the interaction style of an application can have more impact on performance than the communication protocols used for that interaction. My work is motivated by the desire to understand and evaluate the architectural design of network-based application software through principled use of architectural constraints, thereby obtaining the functional, performance, and social properties desired of an architecture. )
二、REST的理解
(1)、Roy Fielding將他對(duì)互聯(lián)網(wǎng)軟件的架構(gòu)原則,定名為REST,即Representation State Transger的縮寫。所以REST指的是一組架構(gòu)約束條件與原則。"如果一個(gè)架構(gòu)符合REST的約束和原則",我們就稱它為RESTful架構(gòu)。
(2)、Representation State Transger有人翻譯為表征狀態(tài)轉(zhuǎn)移,也有人翻譯為表述性狀態(tài)轉(zhuǎn)移,也有人翻譯為表現(xiàn)層狀態(tài)轉(zhuǎn)移,也有人翻譯為"呈現(xiàn)狀態(tài)轉(zhuǎn)移"。我的理解是"表征狀態(tài)轉(zhuǎn)移"。
(3)、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。
三、相關(guān)概念的梳理:
- REST(Respresentational State Transfer):定義了一套基于Web的數(shù)據(jù)交互方式的設(shè)計(jì)風(fēng)格
- RESTful:符合REST風(fēng)格的API就可以叫做RESTful API。注意,本文講到的RESTful API設(shè)計(jì)方法將是基于HTTP和JSON實(shí)現(xiàn)方式,但不論HTTP還是JSON都不是REST的標(biāo)準(zhǔn)。REST只是風(fēng)格,沒(méi)有標(biāo)準(zhǔn)。
- RPC(動(dòng)詞) :REST強(qiáng)調(diào)資源,RPC強(qiáng)調(diào)動(dòng)作,所以REST里面的URI是名詞,RPC多為動(dòng)詞短語(yǔ),然而它們也并不是完全不想管的兩個(gè)東西。
- WebService:一個(gè)貌似很久遠(yuǎn)的概念,有一套它的理論,基于Web的服務(wù)提供者
四、REST關(guān)鍵原則
由于REST定義了應(yīng)該如何正確的使用Web標(biāo)準(zhǔn),例如HTTP和URI。如果你在設(shè)計(jì)應(yīng)用程序的時(shí)能堅(jiān)持REST原則,那就預(yù)示著你將會(huì)得到了一個(gè)優(yōu)質(zhì)的Web架構(gòu)。REST有5條關(guān)鍵原則如下:
- 1.為所有“事物”定義ID
- 2.將所有事物鏈接在一起
- 3.使用標(biāo)準(zhǔn)方法
- 4.資源多重表述
- 5無(wú)狀態(tài)通信
下面讓我們來(lái)詳細(xì)解析一下:
1、為所有"事物"
這里我使用了"事物"來(lái)代替更準(zhǔn)確的術(shù)語(yǔ)"資源"。大家可以想一下人們構(gòu)建的系統(tǒng),通常會(huì)找到一系列的值來(lái)標(biāo)識(shí)關(guān)鍵的抽象,就像數(shù)據(jù)庫(kù)中的"表"里面的"主鍵"一樣,那么在web的世界里面是什么那?大家答對(duì)了,就是URI,RUI構(gòu)成了一個(gè)全局命名的空間。使用URI來(lái)標(biāo)識(shí)你的關(guān)鍵資源意味著它們獲得了一個(gè)全局的、唯一的ID。
記得之前看過(guò)一本書叫<Dont make me think>,里面闡述了一種思想,就是盡量使用那些能夠被絕大多數(shù)人所能理解的規(guī)則,這樣你做的任何東西對(duì)別人來(lái)說(shuō)是沒(méi)有學(xué)習(xí)成本的。同樣的道理,如果在你的application里面定義一個(gè)對(duì)默寫事務(wù)的抽象,別人能瞬間理解(比如消費(fèi)者,應(yīng)該定義為consumer)。更加直觀的講,在淘寶上每一個(gè)商品都有他的一個(gè)固定的ID(URI)。否則,那就扎心了,老鐵。
當(dāng)這樣設(shè)計(jì)的時(shí)候,很多人會(huì)懷疑這樣是否會(huì)直接向外面暴露你的數(shù)據(jù)庫(kù)記錄。但是其實(shí)它和隱藏現(xiàn)實(shí)細(xì)節(jié)之間沒(méi)有任何沖突,通常值得被URI標(biāo)識(shí)的事物——資源——要比數(shù)據(jù)庫(kù)記錄要抽象的多。例如,一個(gè)訂單資源可以由訂單項(xiàng),地址以及其他方面組成。標(biāo)識(shí)所有值的標(biāo)識(shí)事物,領(lǐng)會(huì)這一個(gè)觀念可以引導(dǎo)你創(chuàng)建出在傳統(tǒng)應(yīng)用程序中不常見(jiàn)的資源。一個(gè)流程,一個(gè)談判,一次飯局,這都是應(yīng)該標(biāo)識(shí)的事務(wù)的示例。
下面是一些你可能想到的URI的例子:
http://example.com/customers/1234
http://example.com/orders/2007/10/776654
http://example.com/products/4554
http://example.com/processes/salary-increase-234
基于我創(chuàng)建了便于閱讀的URI——這個(gè)有用的觀點(diǎn),盡管不是RESTful設(shè)計(jì)所必須的,但是你們應(yīng)該會(huì)十分容易的推測(cè)出 URI的含義:他們明顯的"標(biāo)識(shí)"某一數(shù)據(jù)的數(shù)據(jù)項(xiàng)。
繼續(xù)往下看
http://example.com/orders/2007/11
http://example.com/products?color=green
大家看到這兩個(gè)URI看起來(lái)和之前有些不同,因?yàn)樗鼈儾皇菍?duì)一件事物的標(biāo)識(shí),而是對(duì)一類事物的標(biāo)識(shí)(假設(shè)第一個(gè)URI標(biāo)識(shí)了所有2007年11月份的訂單,第二個(gè)標(biāo)識(shí)了綠色產(chǎn)品的集合)。但是這些集合自己也是事物(資源),也應(yīng)該被標(biāo)識(shí)。
PS:使用全局、唯一的命名規(guī)則的好處,既適用于瀏覽器中的Web應(yīng)用,也適用于當(dāng)前的移動(dòng)互聯(lián)網(wǎng)中的app應(yīng)用。
最后總結(jié)一下:使用URI標(biāo)識(shí)所有值得標(biāo)識(shí)的事務(wù),特別是應(yīng)用中提供的所有"高級(jí)"資源,無(wú)論這些資源代表單一數(shù)據(jù)、數(shù)據(jù)項(xiàng)集合、虛擬亦或?qū)嶋H的對(duì)象還是計(jì)算結(jié)果等。
2、將所有事務(wù)連接在一起
這里說(shuō)的是“鏈接”的思想,鏈接在我們HTTP中是非常常見(jiàn)的概念。但是他的用處應(yīng)該不止于此,比如下面的json
{"url":"https://www.hao123.com/"}
但你看見(jiàn)上面的鏈接,應(yīng)用程序可以通過(guò)檢索json,跟蹤鏈接獲取更多的信息。使用URI表示鏈接的優(yōu)雅之處在于,鏈接可以指向不同應(yīng)用、不同服務(wù)器甚至位于南極洲的服務(wù)器。因?yàn)閁RI命名規(guī)范是全球標(biāo)準(zhǔn),構(gòu)成WEB的所有資源都可以互聯(lián)互通。
鏈接的原則還有一個(gè)更重要的方面——應(yīng)用"狀態(tài)"。簡(jiǎn)而言之,實(shí)際上服務(wù)器端為客戶端提供一組鏈接,使客戶端能通過(guò)連接將應(yīng)用從一個(gè)狀態(tài)改變?yōu)榱硪粋€(gè)狀態(tài)。稍后我們會(huì)在另一篇文章探究這個(gè)方面的影響;目前,只需要記住鏈接是構(gòu)成動(dòng)態(tài)應(yīng)用的有效方式。
總結(jié)一下:任何可能的情況下,使用鏈接指引可以被標(biāo)示的資源。也正是鏈接造就了現(xiàn)在的Web。
3、使用標(biāo)準(zhǔn)方法
當(dāng)你在瀏覽器里面輸入一個(gè)uri的時(shí)候,瀏覽器就會(huì)跳轉(zhuǎn)你制定的地址。但是你的瀏覽器是怎么知道該如何操作的那?那是因?yàn)闉g覽器知道所有的資源(uri)都支持同樣的接口。一套同樣的方法,如下圖所示
其中HEAD,TRACE,OPTIONS,CONNECT 在RESTful API 設(shè)計(jì)中不常用,這些Methods具體定義可以在
其中 HEAD,TRACE,OPTIONS,CONNECT 在 RESTful API 設(shè)計(jì)中不常用,這些 Methods 具體定義可以在這里找到。如果需要,可以根據(jù)相關(guān)語(yǔ)意來(lái)實(shí)現(xiàn)具有對(duì)應(yīng)功能的API。
如果你采用RESTful的方式暴露應(yīng)用功能,那這條原則和它同樣也適用于你。
為什么使用標(biāo)準(zhǔn)方法如此重要?從根本上說(shuō),它使你的應(yīng)用稱為Web的一部分——應(yīng)用程序?yàn)閃eb變成Internet上最成功的應(yīng)用所做的貢獻(xiàn),與它添加到Web中的資源數(shù)量成比例。采用RESTful方式,一個(gè)應(yīng)用可能會(huì)向Web中添加數(shù)以百萬(wàn)計(jì)的客戶uri。
統(tǒng)一接口也使用所有理解HTTP應(yīng)用協(xié)議的組件能與你的應(yīng)用交互。通用客戶程序就(generic client)是從從收益的例子,比代理,緩存,網(wǎng)關(guān)等。
總結(jié)一下:為了使客戶端程序能與你的資源相互協(xié)作,資源應(yīng)該正確地實(shí)現(xiàn)默認(rèn)的HTTP協(xié)議(HTTP),也就是使用標(biāo)準(zhǔn)的GET/PUT/POST/DELETE方法。
4、資源多重表述
到目前為止我們忽略了一個(gè)復(fù)雜的問(wèn)題:客戶端程序如何知道怎么處理檢索的導(dǎo)數(shù)據(jù),比如GET或者POST請(qǐng)求的結(jié)果?其實(shí)HTTP采取的方式是允許數(shù)據(jù)處理和操作調(diào)用之間的關(guān)系分離的。換句話說(shuō),如果客戶程序知道如何處理一種特定的數(shù)據(jù)格式,那就可以與所有提供這種格式的資源交互。讓我們?cè)儆靡粋€(gè)例子來(lái)闡述這個(gè)觀點(diǎn),利用HTTP內(nèi)容協(xié)商(content negotiation),客戶端程序可以請(qǐng)求一種特定格式的表述:
GET /customers/1234 HTTP/1.1
Host: example.com
Accept: application/vnd.mycompany.customer+xml
響應(yīng)的返回值可能是一些公司專有的XML格式表述的客戶信息。
假設(shè)客戶端發(fā)起的請(qǐng)求是另外一個(gè)不同的請(qǐng)求,如下:
GET /customers/1234 HTTP/1.1
Host: example.com
Accept: text/json
響應(yīng)的返回值就可能是json格式的
這說(shuō)明為什么理想的情況下,資源表述應(yīng)該采用標(biāo)準(zhǔn)格式,如果客戶端對(duì)HTTP應(yīng)用協(xié)議和數(shù)據(jù)格式都有所"了解"。那么它就可以用一種有意義的方式與世界上任意一個(gè)RESTful HTTP應(yīng)用交互。
在實(shí)際應(yīng)用中,資源多重表述還有其他的好處:如果你為你的資源提供HTML和XML兩種表述方式,那這些資源不僅可以被你的應(yīng)用所用,還可以被任意標(biāo)準(zhǔn)Web瀏覽器所用。你的應(yīng)用信息可以被所有會(huì)使用Web的人獲取到。
總結(jié):針對(duì)不同的需求提供資源多重表述。
五、無(wú)狀態(tài)通信
所謂無(wú)狀態(tài)通信,即所有的資源,都可以通過(guò)URI定位,而且這個(gè)定位與其他資源無(wú)關(guān),也不會(huì)因?yàn)槠渌Y源的變化而改變。有狀態(tài)和無(wú)狀態(tài)的區(qū)別,舉個(gè)例子說(shuō)明下。例如查詢某員工的工資,以為查詢工資是需要登錄系統(tǒng),進(jìn)入查詢工資的頁(yè)面,執(zhí)行相關(guān)操作后,獲取工資的信息,則這種情況吸是有狀態(tài)的,因?yàn)椴樵冋餍诺拿恳徊讲僮鞫家蕾囉谇耙徊降牟僮鳎灰爸貌僮鞑怀晒Γ罄m(xù)操作就無(wú)法執(zhí)行;如果輸入一個(gè)URI即可得到指定某人的工資,則這種情況是無(wú)狀態(tài)的,因?yàn)楂@取工資的信息是不依賴其他資源或者狀態(tài),且這種情況下,某人的工資信息是一個(gè)資源,由一個(gè)URI與之相對(duì)應(yīng),可以通過(guò)HTTP中的GET方法獲取資源,這就是典型的RESTful風(fēng)格。
五、ROS、SOA、REST與RPC
ROA即Resource Oriented Architecture,RESTful架構(gòu)風(fēng)格的服務(wù)是圍繞資源展開(kāi)的,是典型的ROA架構(gòu),雖然ROA與SOA并不沖突,甚至把ROA看做SOA的一種未嘗不可。因此RESful架構(gòu)風(fēng)格的服務(wù)通常被稱之為ROA架構(gòu),很少提及SOA架構(gòu),以便更加顯示的與RPC區(qū)分。
PRC風(fēng)格曾是WebService的主流,最初是基于XML-PRC協(xié)議,后來(lái)漸漸被SOAP協(xié)議取代;但是RPC的風(fēng)格不僅僅可以用HTTP,還可以用TCP或者其他通信協(xié)議。但是PRC風(fēng)格的服務(wù),受服務(wù)器采用語(yǔ)言的束縛比較大。進(jìn)入移動(dòng)互聯(lián)網(wǎng)時(shí)代后,RPC風(fēng)格的服務(wù)很難在移動(dòng)端使用,而RESTful風(fēng)格的服務(wù),由于可以直接以json為載體承載數(shù)據(jù),以HTTP方法為統(tǒng)一接口完成數(shù)據(jù)操作,客戶端的開(kāi)發(fā)部依賴于服務(wù)實(shí)現(xiàn)的技術(shù),移動(dòng)端也可以輕松使用服務(wù),這也加劇了REST取代RPC稱為Web Service的主導(dǎo)
RPC與RESTful的區(qū)別如下面兩個(gè)圖所示
六、總結(jié)
最后我們從REST的名字來(lái)重新分析并總結(jié)一下REST。
REST的全拼是(Respresentational State Transfer) 其中Respresentational指的是資源即Resource 而State Transfer 是狀態(tài)轉(zhuǎn)化,那么我從這兩個(gè)方面來(lái)重新解讀一下
1、資源(Resources)是REST的核心
REST開(kāi)發(fā)又被稱作“面向資源的開(kāi)發(fā)”,這說(shuō)明對(duì)于資源的抽象是設(shè)計(jì)RESTful API的核心內(nèi)容。RESTful API建模的過(guò)程與面向?qū)ο蠼n愃疲且悦~為核心的。這些名詞就是資源,任何可命名的抽象概念都可以定義為一個(gè)資源。對(duì)于業(yè)務(wù)的抽象是設(shè)計(jì)一套好的RESTful API的基礎(chǔ),這就好比建房子打地基,如果地基沒(méi)有打好,后面建的樓就很容易歪掉,其美觀度,可維護(hù)性,可擴(kuò)展性就會(huì)大大折扣。我會(huì)建議在設(shè)計(jì)初期一定要在資源的定義上多花功夫,抽象出適合業(yè)務(wù)發(fā)展的資源。也就是說(shuō)一開(kāi)始要把產(chǎn)品的RESTful風(fēng)格定義下來(lái),后面的擴(kuò)展都可以基于這樣的風(fēng)格延續(xù)下去。
下面是幾條小的建議:
- 理清資源的層次結(jié)構(gòu),比如業(yè)務(wù)針對(duì)的范圍是養(yǎng)雞場(chǎng),那么學(xué)校會(huì)是一級(jí)資源(/school),老師(/school/teachers),學(xué)生(school/students)就是二級(jí)資源。
- 資源盡量用準(zhǔn)備的英文名詞去表達(dá),資源組都是用復(fù)數(shù)來(lái)表示。一個(gè)號(hào)的資源定義一定是不需要解釋的。
2、資源的狀態(tài)轉(zhuǎn)化(State Transfer)
訪問(wèn)一個(gè)網(wǎng)站或者接口,就代表客戶端和服務(wù)器一次交互的過(guò)程,而這個(gè)過(guò)程勢(shì)必會(huì)涉及到數(shù)據(jù)和狀態(tài)的變化。而HTTP協(xié)議又是無(wú)狀態(tài)的,這就意味著所有的狀態(tài)都保存在服務(wù)器。如果某個(gè)客戶端想要做操作服務(wù)器必須通過(guò)某種手段讓服務(wù)器發(fā)生狀態(tài)轉(zhuǎn)換,那么客戶端就可以操作資源,而資源的狀態(tài)轉(zhuǎn)化就轉(zhuǎn)化為對(duì)資源的各種操縱。而這些操作通常是通過(guò)HTTP協(xié)議的四種方法來(lái)實(shí)現(xiàn)的GET/POST/PUT/DELETE。還有其他不常用的方法PATCH/HEAD/OPTIONS。
最后再次重申RESTful 是風(fēng)格,不是標(biāo)準(zhǔn)。