<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      作為架構(gòu)風(fēng)格的 REST 到底是什么

      很多人搞不明白 REST(Representational State Transfer 表述性狀態(tài)轉(zhuǎn)移)原因在于一開始就是把它當(dāng)做設(shè)計風(fēng)格而不是架構(gòu)風(fēng)格來理解,因而一上來就大談特談什么 RESTful API,結(jié)果是只見樹木不見森林。

      僅從設(shè)計的角度去理解 REST(僅把它作為 API 設(shè)計原則),最多僅能理解其資源、表述這些概念,卻很難理解狀態(tài)轉(zhuǎn)移到底是怎么回事。

      要想搞清楚 REST,必須透徹理解三個關(guān)鍵概念:資源、表述、狀態(tài)轉(zhuǎn)移

      REST 架構(gòu)風(fēng)格提出者和 HTTP 1.1 規(guī)范主要設(shè)計者都是同一個人 Roy Fielding。事實上,HTTP 1.1 正是 REST 風(fēng)格的實現(xiàn),因而認(rèn)識 REST 最好的方式是從基于 HTTP 的 Web 應(yīng)用開始。

      場景:

      我們看一個典型場景。

      李小四想在京東上買一部 iPhone。

      首先他在瀏覽器地址欄輸入 www.jd.com(當(dāng)然也可以通過搜索引擎進(jìn)入),打開京東商城首頁,然后在首頁搜索欄輸入“iPhone”,回車,頁面切換到含有 iPhone 關(guān)鍵字的商品列表。

      李小四用鼠標(biāo)點擊其中一個商品,進(jìn)入該商品詳情頁。

      李小四看了看介紹,覺得中意,于是選定顏色、型號、規(guī)格、數(shù)量,點擊“加入購物車”,再點擊“去購物車結(jié)算“,填寫收貨人信息、支付方式、開票信息,點擊“提交訂單”,選擇一種支付方式支付并完成訂單。

      李小四這個人性子比較急,下了單后,每隔一段時間就點開“我的訂單”,點開物流信息看看手機到哪了。

      終于,手機送到了,李小四從快遞員那里簽收后,京東立馬通過微信給他推送一條貨物簽收通知,并且附上開票鏈接。李小四點擊進(jìn)入開票頁面,獲取一張電子發(fā)票。

      資源及其表述:

      在整個購物過程中,李小四與之交互的是一個叫“京東商城”的 Web 應(yīng)用——這是 REST 的作用對象。作為架構(gòu)風(fēng)格的 REST,其作用對象是一個完整的應(yīng)用(或者系統(tǒng))——確切地說是異構(gòu)的分布式應(yīng)用——而不是某一兩個 API。這樣的視角是理解 REST 全貌的關(guān)鍵。

      李小四是如何獲取到他想要的信息的?跑到賣家倉庫去看實體 iPhone?如果這樣,就沒有 Web 什么事了。李小四在瀏覽器地址欄輸入了一串叫 URL 的東西,然后瀏覽器就顯示出京東商城首頁了。

      到底什么是資源?

      本例中,真正的資源是 iPhone、物流、發(fā)票、錢等,但在談?wù)?Web 的時候,我們說的資源一般不是指這些真正的實物資源,而是指存儲在服務(wù)器上的特定數(shù)據(jù),如這里的 iPhone、訂單、物流、發(fā)票、賬戶的數(shù)據(jù)信息

      對于實體 iPhone,我們可以去專賣店看看摸摸,那 Web 上的 iPhone 數(shù)據(jù),我們?nèi)绾握业剿秩绾慰慈绾蚊兀?/p>

      前輩們設(shè)計了個偉大的東西叫 URI,你每臺 iPhone 不是有唯一編號嘛,那 Web 上這些虛擬的數(shù)據(jù)我們也以虛擬物品(資源)的方式給它做唯一編號(標(biāo)識)。雖然是由資源(虛擬數(shù)據(jù))的擁有者來給它做標(biāo)識,但為了統(tǒng)一、通用,前輩們對資源標(biāo)識做了一些約束(協(xié)議),就形成了統(tǒng)一資源標(biāo)識符(Uniform Resource Identifier,URI),這樣便解決了如何找到資源的問題。比如 URL 通過 schema、域名、端口定位到服務(wù)器(資源擁有者),服務(wù)器內(nèi)部再通過 path 和其他參數(shù)找到并處理資源。

      從 URI (URL 是 URI 的一種實現(xiàn)方案)的定義看,它本身就是用來表達(dá)資源的,天生就是名詞特性,只是在實際使用過程中不知為啥就跑歪了,各種 /pathto/getuserinfo 動詞性的 URL 滿天飛(個人認(rèn)為是成也 HTTP 動詞,敗也 HTTP 動詞,更詳細(xì)的分析見后面)。

      資源是找到了,但我們?nèi)绾胃换ツ兀?/p>

      如果是在本機,我們可以通過程序直接操作資源(如通過程序指針直接操作內(nèi)存數(shù)據(jù)),但 Web 是個分布式環(huán)境,指針沒那么長,夠不到對方的內(nèi)存怎么辦?

      于是我們需要在本地(客戶端)擁有一份資源的副本。在 C/S 架構(gòu)中,只有服務(wù)器擁有資源本身,其它客戶端拿到的都是副本,而且擁有者(服務(wù)器)可以決定提供什么樣的副本給客戶端(提供哪些信息、以什么樣的格式提供信息)。

      這種帶特定格式的資源副本就是資源的表述

      作為資源擁有者,服務(wù)器當(dāng)然可以決定提供什么樣的表述形式,但正如 URI 一樣,如果沒有大家都認(rèn)可的、通用的、被廣泛支持的格式,服務(wù)器們各說自話,互相語言不通,那萬維網(wǎng)恐怕就會成為巴比倫塔了。

      于是前輩們又定義了一些通用的資源表述格式,官方話叫媒體類型。Web 上用的最廣泛的媒體類型應(yīng)該是 text/html,其他還有 image/jpeg、application/json、text/xml 等。

      一個資源可以有多種表述(多種媒體類型),也就是說客戶端(如瀏覽器)通過一個 URI(如 URL )可以獲得該資源的多種表述中的一種。那么客戶端和服務(wù)器端是如何溝通以在表述形式上達(dá)成一致呢?

      在 HTTP 中,通過頭信息協(xié)商。HTTP 有一系列 accept 請求頭就是用來干這事的,如 accept、accept-encoding、accept-language。比如 accept: image/webp,image/apng,image/* 告知服務(wù)器“我能處理這些媒體類型,你給其中任意一種給我就行”。服務(wù)器端響應(yīng)頭 content-type 則告知瀏覽器該資源表述的確切媒體類型,如 content-type: image/jpeg 表示它是一張 jpeg 格式的圖片。

      另外,和現(xiàn)實世界一樣,Web 上的資源具有集合特性,比如 iphone,并不是指某一個 iphone,而是指 iphone 集合。從中我們得出以下推論:

      1. 用來表示資源的 URI 應(yīng)該使用名詞復(fù)數(shù)形式;
      2. 對應(yīng)集合的包含關(guān)系(集合中包含子集合),資源具有層級性;
      3. 集合中的元素具有集合范圍內(nèi)的唯一標(biāo)識,通過在 URI 中帶入該唯一標(biāo)識來定位集合中的元素,如 /iphones/123456。

      假設(shè)有這樣一個 url:http://www.jd.com/mobiles/iphones/123456

      首先這里體現(xiàn)了資源的層級性:手機是一個大資源集合,其下包含了 iphone 這個子集合,而通過資源標(biāo)識 123456 定位到某一個 iphone。

      那么,瀏覽器訪問這個 url 時會返回什么呢?

      首先取決于服務(wù)器端決定提供哪些媒體類型,我們假設(shè)服務(wù)器端提供了 text/html、application/json、application/xml 和 image/jpeg 類型。

      瀏覽器會決定請求什么類型呢?

      如果我們在地址欄輸入該 url,瀏覽器一般會發(fā)送如下頭部:accept: text/html,... 要求返回 html 文本。但如果我們在 標(biāo)簽里面寫該 url,瀏覽器會發(fā)送諸如 accept:image/* 要求返回圖片格式——也就是說,取決于我們在哪里用這個 url,這是瀏覽器的工作機制,也是 HTML 的魅力所在(后面分析超媒體時再詳細(xì)分析)。

      你可能會發(fā)現(xiàn),現(xiàn)實中我們見到的多數(shù)不是這樣,更可能是這樣:

      當(dāng)要訪問 html 類型時:http://www.jd.com/mobiles/iphone.html?id=123456(或者是編程語言后綴)

      當(dāng)要訪問圖片時:http://www.jd.com/mobiles/iphones/123456.jpg

      現(xiàn)實中,我們不但在 URL 中寫入動詞來表達(dá)要進(jìn)行的操作,還寫入類型后綴來表達(dá)要什么樣的媒體類型——這兩者都違背了 URI 和 REST 設(shè)計初衷,讓 URI 這個標(biāo)識符同時承擔(dān)了操作和媒體類型,對外暴露了設(shè)計細(xì)節(jié),且該 URI 只能用于極其狹隘的特定場景,違背了可擴展性設(shè)計原則(無法給該 URI 擴展更多的操作能力,也無法擴展其表述能力)。

      現(xiàn)在我們知道如何定位資源和如何傳遞(展示)資源,接下來的問題是,客戶端如何操作資源呢?客戶端無法通過操作表述(資源副本)改變資源狀態(tài),必須通過和服務(wù)器端交互來實現(xiàn)。

      在 HTTP 中是通過幾個通用的動詞來表達(dá)客戶端的操作意圖的,最典型的 CRUD,對應(yīng) HTTP 動詞(Method)POST、GET、PUT/PATCH、DELETE
      狀態(tài)轉(zhuǎn)移:

      通過 URL 定位資源,通過 HTTP 動詞操作資源,通過狀態(tài)碼表示操作結(jié)果——現(xiàn)在大部分聲稱 RESTful API 的也都是做到了且僅做到了這些,大部分分析 REST 的文章也是到此便結(jié)束了,但實際上這只是開始。

      相比于資源表述,REST 中更重要的第二部分是狀態(tài)轉(zhuǎn)移。Roy Fielding 提出一個術(shù)語叫將超媒體作為應(yīng)用狀態(tài)的引擎(Hypermedia As The Engine Of Application State)。這句話過于拗口,翻譯過來更是難以理解,結(jié)果被很多人忽略掉了,但這正是 REST 的精髓。

      我們先解釋下這個術(shù)語。

      超媒體:就是我們再熟悉不過的超鏈接,HTML 標(biāo)簽中的 a、script、img、link等都屬于超媒體鏈接。

      應(yīng)用狀態(tài):這里明確指出是應(yīng)用的狀態(tài)而不是資源的。比如上面購物場景中的京東商城就是一個 Web 應(yīng)用,而應(yīng)用的狀態(tài)則是該應(yīng)用在某時刻呈現(xiàn)出來的樣子(各個頁面)。

      引擎:驅(qū)動狀態(tài)改變(遷移)的東西,說得白話一點就是京東商城的一個個超鏈接(主要是只 a 標(biāo)簽鏈接)驅(qū)動其從一個頁面切換到另一個頁面。

      應(yīng)用為何要發(fā)生狀態(tài)轉(zhuǎn)移?為了完成一個完整的活動,比如上面的購物。應(yīng)用本質(zhì)上是一個有限狀態(tài)機,其中囊括的一個個活動就是一個個工作流,應(yīng)用的狀態(tài)就是工作流中的節(jié)點。我們把上面購物過程畫出來如下(只畫了主流程,實際中會有很多分支流程,比如用戶付款后取消訂單、簽收后退貨等):

      李小四購物流程圖

      這里涉及到一次購物活動(一個大的流程圖)中的三個子流程:購物(下單-支付)、查看物流、開發(fā)票。每個節(jié)點對應(yīng)應(yīng)用的一個狀態(tài)(也就是頁面,前兩個是京東商城的,后一個是微信的)。

      回想一下李小四是怎樣在這些頁面(應(yīng)用狀態(tài))間跳來跳去的?不停地在地址欄輸入 URL?如果沒有超鏈接(那個小小的 a)恐怕就只能這樣了。如果沒有超鏈接,京東首頁就不是現(xiàn)在這個樣子了,而是一坨長長的 URL 列表,且附上難看的流程圖告訴用戶要想買一部 iPhone 得按照順序依次在地址欄輸入哪些 URL——這是多么令人崩潰的事情。

      所以超鏈接是個偉大的發(fā)明,它使資源(的表述)之間建立聯(lián)系,用戶能夠從應(yīng)用的一個狀態(tài)轉(zhuǎn)移到另一個狀態(tài),進(jìn)而完成整個工作流。而且,這種轉(zhuǎn)移是發(fā)現(xiàn)式的,即應(yīng)用的狀態(tài)切換不是既定的,一個狀態(tài)的下一個狀態(tài)可能并不確定,比如李小四打開京東商城首頁后,對某款手表感興趣,于是點擊其鏈接進(jìn)入手表詳情頁——結(jié)果買了一款手表而不是 iPhone。

      那么,資源的表述應(yīng)用的狀態(tài)之間又是什么關(guān)系呢?

      應(yīng)用的狀態(tài)就是資源的表述,或者說應(yīng)用是通過不同的資源表述來展現(xiàn)自己的。應(yīng)用狀態(tài)的轉(zhuǎn)移就是不同的資源表述之間或者同一個資源的不同狀態(tài)的表述之間的轉(zhuǎn)移。

      上面購物流程中,首頁是一個特殊的資源;商品列表、商品詳情是不同層次的商品資源;添加購物車生成新的購物車資源(或者更新購物車資源),從創(chuàng)建購物車到購物車詳情頁屬于購物車資源的不同狀態(tài)之間的轉(zhuǎn)移;下單操作創(chuàng)建了新的訂單資源,支付則產(chǎn)生支付資源,并且在京東商城應(yīng)用內(nèi)部產(chǎn)生了一系列新資源比如物流資源;訂單簽收后開具發(fā)票則產(chǎn)生了發(fā)票資源。

      至此我們發(fā)現(xiàn),整個 Web 應(yīng)用的核心仍然是資源,但既不是某一個資源,也不是某幾個毫無關(guān)聯(lián)的資源,而是一系列通過超鏈接建立聯(lián)系、能夠形成工作流來完成一系列活動的有機資源池。

      在資源的表述中納入超鏈接,讓資源的表述帶有相關(guān)資源的 URI,從而讓應(yīng)用能夠自動進(jìn)行狀態(tài)轉(zhuǎn)移,這種媒體類型(表述)叫超媒體類型。HTML(XHTML) 是最常見的一種超媒體類型,而且是超媒體文本類型(超文本)。雖然 XHTML 基于 XML,但 XML(以及 JSON)不是超媒體類型,它們的原生語義中不帶有超鏈接,無法從 XML 形式的資源表述進(jìn)入其它資源表述。

      XHTML 之所以是超媒體類型,是它在 XML 基礎(chǔ)上做了語義化(標(biāo)記)處理,HTML(XHTML)處理器知道,a 標(biāo)簽表示超鏈接,點擊可以打開新頁面,標(biāo)簽表示需要從其指向的 URI 獲取圖像格式的資源表述,發(fā)起 HTTP 請求時會帶上諸如 accept: image/*(而不是 text/html)的請求頭。

      基于 XML 的另一個廣泛使用的超媒體類型是 Atom。

      我們也可以基于 XML 和 JSON 來設(shè)計自己的超媒體類型嗎?當(dāng)然可以。比如我們可以定義如下 JSON 格式:

      {
      	"id": 123,
      	"money": 3000.00,
      	...
      	"links": [{
      		"rel": "mydomain/logistics",
      		"uri": "https://www.domain.com/v1/logistics/47589"
      	}]
      }
      

      其中 links 表示相關(guān)資源鏈接列表,這里給出了本訂單相關(guān)的物流資源鏈接。該 JSON 是一個超媒體類型,它不但表述了 123 這個訂單資源的信息,還給出了指向相關(guān)物流資源的鏈接。一般地,我們還要編寫對應(yīng)的 JSON Schema,讓其它 JSON 解析器能夠理解我們定義的類型協(xié)議。假如我們將該超媒體類型定義為 application/my.hyperproto+json,能夠處理該媒體類型的客戶端發(fā)起 HTTP 請求時請求頭帶上 accept:application/my.hyperproto+json,我們服務(wù)器響應(yīng)時帶上 content-type:application/my.hyperproto+json,雙方便可以自如地你來我往了(這也正是設(shè)計 RESTful API 的一個要點,雖然事實上被大部分實現(xiàn)者忽略了)。

      現(xiàn)實:

      回顧歷史,最早人們并沒有重視 HTTP 動詞和超媒體類型,通過在 URI 中添加動詞和類型后綴來表達(dá)意圖,早期一些瀏覽器和庫甚至不支持除了 GET 和 POST 之外的動詞。URI 被動詞和類型后綴污染的后果是它不再是“URI”(資源標(biāo)識),而是操作者意圖傳輸工具,某些角度說,它影響了 URI 的通用性和可擴展性。

      還有一種對 HTTP 協(xié)議的退化使用是 XML-RPC,通過一個 URL 搞定一切,其他所有的信息都寫在 XML 請求體中——在這里,HTTP 僅僅被當(dāng)做傳輸協(xié)議而不是應(yīng)用協(xié)議來使用,之
      所以使用 HTTP 僅僅是因為它被各種庫廣泛支持,較好地滿足了異構(gòu)系統(tǒng)環(huán)境。

      后來,可能是一些流行框架的支持,大家趕時髦式地談?wù)撈?RESTful API 起來。這些所謂的 RESTful API 不過是把動詞和類型后綴從 URI 中拿走了,給 URI“正了名”,重新用起 HTTP Method。他們并沒有用起超媒體特性,HTTP 響應(yīng)類型僅僅是普通的 XML 或 JSON,資源表述本身不能驅(qū)動工作流的行進(jìn),使用者仍然需要通過帶外方式(文檔)獲取相關(guān)資源 URI。

      我想,這可能是 REST 和 HTTP 協(xié)議自身特質(zhì)造成的。

      將操作(動作)極度抽象化(通用化)是一項偉大的設(shè)計,但“成也蕭何敗也蕭何”。一方面 HTTP 動詞高度抽象化(標(biāo)準(zhǔn)化、通用化),迫使開發(fā)者需要絞盡腦汁去把現(xiàn)實世界中成百上千的操作映射到那幾個動詞上——這不是一項簡單的思想活動,同時它還要求開發(fā)者需合理的定義“資源”,有些可能是極度抽象的。另一方面,和嚴(yán)謹(jǐn)?shù)膭釉~形成鮮明對比的是 URI(URL)的極度靈活性,開發(fā)者可以任意書寫 URL,只要能定位到正確的服務(wù)器,而后便是“我的地盤我做主”,沒有任何硬性約束要求 URL 里面只能出現(xiàn)名詞。于是為了少死幾個腦細(xì)胞,開發(fā)人員普遍性地忽略掉 HTTP 動詞(甚至忽略掉了媒體類型協(xié)商),把這些信息一股腦全塞入那個“萬能”的 URL 里面。

      使用超媒體的一個困惑是,當(dāng)我們使用自定義的超媒體類型時,客戶端需要進(jìn)行額外的解析工作,還不如直接傳遞大家都認(rèn)識的 JSON 或 XML 來得短平快。

      另外,通過超媒體驅(qū)動,意味著應(yīng)用(系統(tǒng))僅需要對外公布少數(shù)幾個入口 URI,其它 URI 都是通過上游資源表述的超鏈接獲取的。那么,我們到底要暴露哪些入口 URI 呢?這又是一個需要深入思考的問題,而人都是懶惰的。

      不過,REST 給我們設(shè)計 API 提供了一些啟示或原則。

      • 在系統(tǒng)的頂層架構(gòu)上,面向資源而不是操作去規(guī)劃系統(tǒng),能站在全局的視角思考系統(tǒng)構(gòu)架,讓系統(tǒng)規(guī)劃和對外暴露的 API 盡可能趨向穩(wěn)定。
      • URI 僅僅代表資源,通過 HTTP 動詞規(guī)范化操作,能倒逼我們更合理地劃分資源邊界,使得系統(tǒng)更模塊化、層次化。另外,它能讓我們更深層次地思考“資源”,比如登錄,好像是個純動詞,但如果進(jìn)一步思考,登錄這個行為是為了創(chuàng)建會話,對應(yīng)的登出則是銷毀會話,因而我們操作的實際上是“會話”(Session)資源。
      • 盡可能使用超媒體類型。通過超鏈接對外暴露 URI 的一個好處是將具體的 URI 細(xì)節(jié)隱藏起來,比如上面的 JSON 中,客戶端僅關(guān)心 rel 的值,然后提取相應(yīng)的 uri 的值,這里 rel 是不變的,但 uri 可能會發(fā)生變化(比如我們的某個服務(wù)外包給第三方了),當(dāng) URI變化時,我們無需廣而告之所有的客戶端你要改鏈接哈,否則服務(wù)不可用了哈。

      總結(jié):

      最后我們總結(jié)下對 REST 中資源、表述、狀態(tài)轉(zhuǎn)移的理解:

      • 資源是服務(wù)器端的原始數(shù)據(jù),比如訂單數(shù)據(jù),它是應(yīng)用的核心。資源通過 URI 對外暴露自身;
      • 在分布式應(yīng)用中(如 Web),客戶端無法直接觸達(dá)資源本身,能觸達(dá)的是資源的表述。表述是某種格式的資源副本;
      • 客戶端無法通過修改表述(資源副本)來改變資源本身。服務(wù)器端擁有資源的控制權(quán),它決定可以提供哪些表述給客戶端,也能決定提供什么樣的操作(動詞);
      • 客戶端通過通用動詞來獲取資源表述以及修改資源狀態(tài);
      • 狀態(tài)是指應(yīng)用的狀態(tài),狀態(tài)轉(zhuǎn)移體現(xiàn)為應(yīng)用中工作流程的行進(jìn)(從一個頁面切換到另一個頁面);
      • 狀態(tài)轉(zhuǎn)移是通過超鏈接驅(qū)動的。超鏈接由資源的表述攜帶,這種攜帶了超鏈接的表述稱為超媒體;
      • 超媒體使得應(yīng)用能夠自我驅(qū)動狀態(tài)轉(zhuǎn)移(而不需要通過帶外方式);


      posted @ 2020-07-26 18:00  林子er  閱讀(645)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 久久综合九色综合97婷婷 | 人成午夜免费大片| 永久免费在线观看蜜桃视频| 无码国产偷倩在线播放| 绍兴市| 亚洲精品国产摄像头| 亚洲精品国自产拍影院| 日韩丝袜人妻中文字幕| 十八禁国产精品一区二区| 久久亚洲精品无码va白人极品| 99热门精品一区二区三区无码| 国产真人做受视频在线观看| 亚洲最大福利视频网| 中文字幕乱码人妻综合二区三区| 久久精品色一情一乱一伦| 亚洲中文无码永久免费| 亚洲av成人一区国产精品| 亚洲AV日韩AV激情亚洲| 国产综合久久久久久鬼色| 乱码视频午夜在线观看| 国产亚洲一区二区三区成人| 亚洲精品日本久久一区二区三区| 午夜在线欧美蜜桃| 成人三级视频在线观看不卡| 四虎永久精品免费视频| 狠狠综合久久综合88亚洲| 石泉县| 国产高清小视频一区二区| 欧美丰满熟妇xxxx性大屁股| 亚洲美免无码中文字幕在线| 最新日韩精品视频在线| 色秀网在线观看视频免费| 乱人伦中文字幕成人网站在线| 92精品国产自产在线观看481页| 国产精品高清中文字幕| 包头市| 国产真人做受视频在线观看| 久久九九精品99国产精品| 国内熟妇人妻色在线视频| 曰批免费视频播放免费| 亚洲精品国产美女久久久|