溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

HTTP的傳輸編碼是什么

發(fā)布時(shí)間:2021-12-01 15:49:54 來(lái)源:億速云 閱讀:130 作者:柒染 欄目:云計(jì)算

本篇文章給大家分享的是有關(guān)HTTP的傳輸編碼是什么,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。

什么是傳輸編碼?

傳輸編碼在 HTTP 的報(bào)文頭中,使用 Transfer-Encoding 首部進(jìn)行標(biāo)記,它就是指明當(dāng)前使用的傳輸編碼。

Transfer-Encoding 會(huì)改變報(bào)文的格式和傳輸?shù)姆绞?,使用它不但不?huì)減少內(nèi)容傳輸?shù)拇笮。踔吝€有可能會(huì)使傳輸變大,看似是一個(gè)不環(huán)保的做法,但是其實(shí)是為了解決一些特殊問(wèn)題。

簡(jiǎn)單來(lái)說(shuō),傳輸編碼必須配合持久連接去使用,為了在一個(gè)持久連接中,將數(shù)據(jù)分塊傳輸,并標(biāo)記傳輸結(jié)束而設(shè)計(jì)的,后面會(huì)詳細(xì)講解。

在早年間的設(shè)計(jì)里,和內(nèi)容編碼使用 Accept-Encoding 來(lái)標(biāo)記客戶端接收的壓縮編碼類(lèi)型一樣,傳輸編碼還需要配合 TE 這個(gè)請(qǐng)求報(bào)文頭來(lái)使用,用于指定支持的傳輸編碼。但是在最新的 HTTP/1.1 協(xié)議規(guī)范中,只定義了一種傳輸編碼:分塊編碼(chunked),所以并不需要再依賴 TE 這個(gè)頭部。

這些細(xì)節(jié),后面都會(huì)講到。既然傳輸編碼和持久連接是息息相關(guān)的,那我們就先來(lái)了解一下什么是持久連接。

持久連接(Persistent Connection)

持久連接通俗來(lái)講,就是長(zhǎng)連接,英文叫 Persistent Connection,其實(shí)按字面意思理解就好了。

在早期的 HTTP 協(xié)議中,傳輸數(shù)據(jù)的順序大致分為發(fā)起請(qǐng)求、建立連接、傳輸數(shù)據(jù)、關(guān)閉連接等步驟,而持久連接,就是去掉關(guān)閉連接這個(gè)步驟,讓客戶端和服務(wù)端可以繼續(xù)通過(guò)此次連接傳輸內(nèi)容。

這其實(shí)也是為了提高傳輸效率,我們知道 HTTP 協(xié)議是建立在 TCP 協(xié)議之上的,自然有 TCP 一樣的三次握手、慢啟動(dòng)等特性,這樣每一次連接其實(shí)都是一次寶貴的資源。為了盡可能的提高 HTTP 的性能,使用持久連接就顯得很重要了。為此在 HTTP 協(xié)議中,就引入了相關(guān)的機(jī)制。

在早期的 HTTP/1.0 協(xié)議中并沒(méi)有持久連接,持久連接的概念是在后期才引入的,當(dāng)時(shí)是通過(guò) Connection:Keep-Alive 這個(gè)頭部來(lái)標(biāo)記實(shí)現(xiàn),用于通知客戶端或服務(wù)端相對(duì)的另一端,在發(fā)送完數(shù)據(jù)之后,不要斷開(kāi) TCP 連接,之后還需要再次使用。

而在 HTTP/1.1 協(xié)議中,發(fā)現(xiàn)持久連接的重要性了,它規(guī)定所有的連接必須都是持久的,除非顯式的在報(bào)文頭里,通過(guò) Connection:close 這個(gè)首部,指定在傳輸結(jié)束之后會(huì)關(guān)閉此連接。

實(shí)際上在 HTTP/1.1 中Connect 這個(gè)頭部已經(jīng)沒(méi)有 Keep-Alive 這個(gè)取值了,由于歷史原因,很多客戶端和服務(wù)端,依然保留了這個(gè)報(bào)文頭。

長(zhǎng)連接帶來(lái)了另外一個(gè)問(wèn)題,如何判定當(dāng)前數(shù)據(jù)發(fā)送完成。

判斷傳輸完成

在早期不支持持久連接的時(shí)候,其實(shí)是可以依靠連接斷開(kāi)來(lái)判定當(dāng)前傳輸已經(jīng)結(jié)束,大部分瀏覽器也是這么干的,但這并不是規(guī)范的操作。應(yīng)該使用 Content-Length 這個(gè)頭部,來(lái)指定當(dāng)前傳輸?shù)膶?shí)體內(nèi)容長(zhǎng)度。

下面舉個(gè)例子,在保持持久連接的情況下,依賴 Content-Length 來(lái)確定數(shù)據(jù)發(fā)送完畢。

Content-Length 在這里起到了一個(gè)響應(yīng)實(shí)體已經(jīng)發(fā)送結(jié)束的判斷依據(jù)。這樣的情況下,我們就要求 Content-Length 必須和內(nèi)容實(shí)體的長(zhǎng)度一致,如果不一致,就會(huì)出現(xiàn)各種問(wèn)題。

如上圖所示,如果 Content-Length 小于內(nèi)容實(shí)體的長(zhǎng)度,則會(huì)截?cái)?,反之則無(wú)法判定當(dāng)前響應(yīng)已經(jīng)結(jié)束,會(huì)將請(qǐng)求持續(xù)掛起造成 Padding 狀態(tài)。

理想情況下,我們?cè)陧憫?yīng)一個(gè)請(qǐng)求的時(shí)候,就需要知道它的內(nèi)容實(shí)體的大小。但是在實(shí)際應(yīng)用中,有些時(shí)候內(nèi)容實(shí)體的長(zhǎng)度并沒(méi)有那么容易獲得。例如內(nèi)容實(shí)體來(lái)自網(wǎng)絡(luò)文件、或者是動(dòng)態(tài)生成的。這個(gè)時(shí)候如果依然想要提前獲取到內(nèi)容實(shí)體的長(zhǎng)度,只能開(kāi)一個(gè)足夠大的 Buffer,等內(nèi)容全部緩存好了再計(jì)算。

但這并不是一個(gè)好的方案,全部緩存到 Buffer 里,第一會(huì)消耗更多的內(nèi)存,第二也會(huì)更耗時(shí),讓客戶端等待過(guò)久。

此時(shí)就需要一個(gè)新的機(jī)制,不依賴 Content-Length 的值,來(lái)判定當(dāng)前內(nèi)容實(shí)體是否傳輸完成,此時(shí)就需要 Transfer-Encoding 這個(gè)頭部來(lái)判定。

Transfer-Encoding:chunked

前面也提到,Transfer-Encoding 在最新的 HTTP/1.1 協(xié)議里,就只有 chunked 這個(gè)參數(shù),標(biāo)識(shí)當(dāng)前為分塊編碼傳輸。

分塊編碼傳輸既然只有一個(gè)可選的參數(shù),我們就只需要指定它為 Transfer-Encoding:chunked ,后續(xù)我們就可以將內(nèi)容實(shí)體包裝一個(gè)個(gè)塊進(jìn)行傳輸。

分塊傳輸?shù)囊?guī)則:

1. 每個(gè)分塊包含一個(gè) 16 進(jìn)制的數(shù)據(jù)長(zhǎng)度值和真實(shí)數(shù)據(jù)。

2. 數(shù)據(jù)長(zhǎng)度值獨(dú)占一行,和真實(shí)數(shù)據(jù)通過(guò) CRLF(\r\n) 分割。

3. 數(shù)據(jù)長(zhǎng)度值,不計(jì)算真實(shí)數(shù)據(jù)末尾的 CRLF,只計(jì)算當(dāng)前傳輸塊的數(shù)據(jù)長(zhǎng)度。

4. 最后通過(guò)一個(gè)數(shù)據(jù)長(zhǎng)度值為 0 的分塊,來(lái)標(biāo)記當(dāng)前內(nèi)容實(shí)體傳輸結(jié)束。

在這個(gè)例子中,首先在響應(yīng)頭部里標(biāo)記了 Transfer-Encoding: chunked,后續(xù)先傳遞了第一個(gè)分塊 “0123456780”,長(zhǎng)度為 b(11 的十六進(jìn)制),之后分別傳輸了 “Hello CxmyDev” 和 “123”,最后以一個(gè)長(zhǎng)度為 0 的分塊標(biāo)記當(dāng)前響應(yīng)結(jié)束。

chunked 的拖掛

當(dāng)我們使用 chunked 進(jìn)行分塊編碼傳輸?shù)臅r(shí)候,傳輸結(jié)束之后,還有機(jī)會(huì)在分塊報(bào)文的末尾,再追加一段數(shù)據(jù),此數(shù)據(jù)稱為拖掛(Trailer)。

拖掛的數(shù)據(jù),可以是服務(wù)端在末尾需要傳遞的數(shù)據(jù),客戶端其實(shí)是可以忽略并丟棄拖掛的內(nèi)容的,這就需要雙方協(xié)商好傳輸?shù)膬?nèi)容了。

在拖掛中可以包含附帶的首部字段,除了 Transfer-Encoding、Trailer 以及 Content-Length 首部之外,其他 HTTP 首部都可以作為拖掛發(fā)送。

一般我們會(huì)使用拖掛來(lái)傳遞一些在響應(yīng)報(bào)文開(kāi)始的時(shí)候,無(wú)法確定的某些值,例如:Content-MD5 首部就是一個(gè)常見(jiàn)的在拖掛中追加發(fā)送的首部。和長(zhǎng)度一樣,對(duì)于需要分塊編碼傳輸?shù)膬?nèi)容實(shí)體,在開(kāi)始響應(yīng)的時(shí)候,我們也很難算出它的 MD5 值。

注意這里在頭部增加了 Trailder,用以指定末尾還會(huì)傳遞一個(gè) Content-MD5 的拖掛首部,如果有多個(gè)拖掛的數(shù)據(jù),可以使用逗號(hào)進(jìn)行分割。

內(nèi)容編碼和傳輸編碼結(jié)合

內(nèi)容編碼和傳輸編碼一般都是配合使用的。我們會(huì)先使用內(nèi)容編碼,將內(nèi)容實(shí)體進(jìn)行壓縮,然后再通過(guò)傳輸編碼分塊發(fā)送出去??蛻舳私邮盏椒謮K的數(shù)據(jù),再將數(shù)據(jù)進(jìn)行重新整合,還原成最初的數(shù)據(jù)。

傳輸編碼小結(jié)

我們對(duì)傳輸編碼應(yīng)該有一定的了解了。這里簡(jiǎn)單總結(jié)一下:

1. 傳輸編碼使用 Transfer-Encoding 首部進(jìn)行標(biāo)記,在最新的 HTTP/1.1 協(xié)議里,它只有 chunked 這一個(gè)取值,表示分塊編碼。

2. 傳輸編碼主要是為了解決持久連接里將數(shù)據(jù)分塊傳輸之后,判定內(nèi)容實(shí)體傳輸結(jié)束。

3. 分塊的格式:數(shù)據(jù)長(zhǎng)度(16進(jìn)制)+ 分塊數(shù)據(jù)。

4. 如果還有額外的數(shù)據(jù),可以在結(jié)束之后,使用 Trailer 進(jìn)行拖掛傳輸額外的數(shù)據(jù)。

5. 傳輸編碼通常會(huì)配合內(nèi)容編碼一起使用。

此外,傳輸編碼應(yīng)該是所有 HTTP/1.1 的標(biāo)準(zhǔn)實(shí)現(xiàn),應(yīng)該都有支持,如果收到無(wú)法理解的經(jīng)過(guò)傳輸編碼的報(bào)文,應(yīng)該直接返回 501 Unimplemented 這個(gè)狀態(tài)碼來(lái)回復(fù)即可。

以上就是HTTP的傳輸編碼是什么,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI