Http協(xié)議發(fā)展簡史以及常見面試題解析
本文轉(zhuǎn)載自微信公眾號「Java大廠面試官」,作者laker 。轉(zhuǎn)載本文請聯(lián)系Java大廠面試官公眾號。
目錄
- 什么是HTTP協(xié)議
- HTTP協(xié)議發(fā)展簡史
- HTTP 0.9 單行協(xié)議
- HTTP 1.0 構(gòu)建擴(kuò)展性
- HTTP 1.1 標(biāo)準(zhǔn)化協(xié)議
- HTTP 2.0 更高性能的協(xié)議
- 問題
- 1.http1.1長連接keep-alive和http2.0的多路復(fù)用有什么區(qū)別?
- 2.什么是流水線(管道機(jī)制)?
- 3.現(xiàn)代瀏覽器在與服務(wù)器建立了一個(gè) TCP 連接后是否會在一個(gè) HTTP 請求完成后斷開?
- 4.一個(gè) TCP 連接可以對應(yīng)幾個(gè) HTTP 請求?
- 5.一個(gè) TCP 連接中 HTTP 請求發(fā)送可以一起發(fā)送么(比如一起發(fā)三個(gè)請求,再三個(gè)響應(yīng)一起接收)?
什么是HTTP協(xié)議
超文本傳輸協(xié)議(HTTP)是Internet上最普遍和廣泛采用的應(yīng)用程序協(xié)議之一:它是客戶端和服務(wù)器之間的通用語言,可實(shí)現(xiàn)現(xiàn)代Web。從簡單的一個(gè)關(guān)鍵字和文檔路徑開始,它不僅成為瀏覽器的選擇協(xié)議,而且?guī)缀醭蔀樗信cInternet連接的軟件和硬件應(yīng)用程序的選擇協(xié)議。
HTTP具有四個(gè)版本:
- HTTP / 0.9
- HTTP / 1.0
- HTTP / 1.1
- HTTP / 2.0
時(shí)至今日,常用的版本是HTTP / 1.1,未來的發(fā)展版本是HTTP / 2.0。
HTTP協(xié)議發(fā)展簡史
HTTP 0.9 單行協(xié)議
HTTP協(xié)議的第一個(gè)簡單實(shí)現(xiàn),僅支持獲取網(wǎng)頁。一開始都沒有版本號,為了區(qū)分其他版本,后來被稱為0.9。HTTP / 0.9非常簡單:請求由一行組成,并以唯一的方法GET開頭,后跟資源的路徑。
- GET /mypage.html
- <HTML>
- A very simple HTML page
- </HTML>
從1991年開始,HTTP就有了自己的生命,并在接下來的幾年中迅速發(fā)展。
緣分吶❤️,我也是1991年破殼。
核心功能:
- 簡單的客戶端-服務(wù)器,請求-響應(yīng)協(xié)議。
- 支持的方法:只有GET。
- ASCII協(xié)議,通過TCP / IP鏈接運(yùn)行。
- 設(shè)計(jì)用于傳輸超文本文檔(HTML)。
- 每次請求后,服務(wù)器和客戶端之間的連接都會關(guān)閉。
- 沒有HTTP標(biāo)頭(無法傳輸其他內(nèi)容類型文件),沒有狀態(tài)/錯誤代碼,沒有URL,沒有版本控制
這個(gè)我表示我生活在現(xiàn)代,目前我所經(jīng)歷的都沒碰到過。。。直接跳過,不研究👄
HTTP 1.0 構(gòu)建擴(kuò)展性
HTTP / 0.9協(xié)議非常有限,瀏覽器和服務(wù)器都迅速增加擴(kuò)展性,使其變的更加通用。
1996年5月,HTTP工作組(HTTP-WG)發(fā)布了RFC 1945,此版本添加了許多補(bǔ)充數(shù)據(jù)字段,稱為規(guī)范的標(biāo)頭。這允許其他信息在客戶端和服務(wù)器之間以及請求和后續(xù)頁面之間傳遞。
- GET /mypage.html HTTP/1.0
- User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)
- 200 OK
- Date: Tue, 15 Nov 1994 08:12:31 GMT
- Server: CERN/3.0 libwww/2.17
- Content-Type: text/html
- <HTML>
- A page with an image
- <IMG SRC="/myimage.gif">
- </HTML>
核心功能:
- 提供的標(biāo)頭字段包括有關(guān)請求和響應(yīng)的豐富元數(shù)據(jù)(HTTP版本號,狀態(tài)代碼,內(nèi)容類型)
- 響應(yīng):不限于超文本(Content-Type標(biāo)頭提供了傳輸普通HTML文件以外的文件的功能,例如腳本,樣式表,媒體)
- 支持的方法:GET,HEAD,POST
- 請求可能包含多個(gè)換行符分隔的標(biāo)頭字段。
- 響應(yīng)對象以響應(yīng)狀態(tài)行為前綴。
- 響應(yīng)對象具有自己的一組由換行符分隔的標(biāo)頭字段。
- 每次請求后,服務(wù)器和客戶端之間的連接都會關(guān)閉。
nginx默認(rèn)還是http1.0協(xié)議,剛好前幾天碰到個(gè)問題【1.0不支持分塊傳輸】,具體可參見:
nginx 下載文件 upstream sent invalid chunked response while reading upstream 錯誤
HTTP 1.1 標(biāo)準(zhǔn)化協(xié)議
HTTP / 1.1標(biāo)準(zhǔn)解決了早期版本中的許多協(xié)議歧義,并引入了許多關(guān)鍵的性能優(yōu)化:
- 保持活動連接
- 分塊編碼傳輸
- 字節(jié)范圍請求
- 附加緩存機(jī)制
- 傳輸編碼
- 請求流水線(管道機(jī)制)
如今,大多數(shù)瀏覽器都支持1.0和1.1的實(shí)現(xiàn),新瀏覽器默認(rèn)使用1.1,但是如果有需要的話,還可以回退到早期版本。RFC定義明確指出的一件事是,HTTP協(xié)議的所有實(shí)現(xiàn)都應(yīng)向后兼容。也就是說,實(shí)現(xiàn)HTTP /1.1規(guī)范的瀏覽器應(yīng)該能夠從服務(wù)器接收1.0響應(yīng)。相反,服務(wù)器端的1.1實(shí)現(xiàn)也應(yīng)該能夠響應(yīng)來自1.0瀏覽器的請求。
將HTTP轉(zhuǎn)變?yōu)檎降腎ETF Internet標(biāo)準(zhǔn)的工作與圍繞HTTP / 1.0的文檔編制工作并行進(jìn)行,大約持續(xù)了四年時(shí)間:1995年至1999年。
實(shí)際上,第一個(gè)正式的HTTP / 1.1標(biāo)準(zhǔn)是在RFC 2068,于1997年1月正式發(fā)布,距HTTP / 1.0發(fā)布大約六個(gè)月。然后,兩年半之后的1999年6月,許多改進(jìn)和更新被納入該標(biāo)準(zhǔn),并以RFC 2616的形式發(fā)布。
- GET /static/img/header-background.png HTTP/1.1
- Host: developer.cdn.mozilla.net
- User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
- Accept: */*
- Accept-Language: en-US,en;q=0.5
- Accept-Encoding: gzip, deflate, br
- Referer: https://developer.mozilla.org/en-US/docs/Glossary/Simple_header
- 200 OK
- Age: 9578461
- Cache-Control: public, max-age=315360000
- Connection: keep-alive
- Content-Length: 3077
- Content-Type: image/png
- Date: Thu, 31 Mar 2016 13:34:46 GMT
- Last-Modified: Wed, 21 Oct 2015 18:27:50 GMT
- Server: Apache
- (image content of 3077 bytes)
核心功能:
- 可以重用連接,從而節(jié)省了多次重新打開連接的時(shí)間。
- 添加了流水線,允許在完全傳輸?shù)谝粋€(gè)請求的答案之前發(fā)送第二個(gè)請求,從而降低了通信延遲。
- 現(xiàn)在也支持分塊編碼傳輸。
- 已經(jīng)引入了其他緩存控制機(jī)制。
- 引入了內(nèi)容協(xié)商,包括語言,編碼或類型,并使客戶端和服務(wù)器可以就最適當(dāng)?shù)膬?nèi)容達(dá)成共識。
- 現(xiàn)在可以在同一IP地址托管不同域的功能允許服務(wù)器托管。
HTTP / 1.1更改了HTTP協(xié)議的語義,默認(rèn)情況下使用長連接。這意味著,除非另有說明(通過Connection: close標(biāo)頭),否則 服務(wù)器應(yīng)默認(rèn)保持連接打開。
但是,此功能也已反向移植到HTTP / 1.0,并通過Connection: Keep-Alive標(biāo)頭啟用。因此,如果您使用的是HTTP / 1.1,從技術(shù)上講,您不需要 Connection: Keep-Alive標(biāo)頭,但是許多客戶端仍然選擇提供它。
自2005年以來,可用于網(wǎng)頁的API集大大增加,其中一些API創(chuàng)建了針對特定目的的HTTP協(xié)議擴(kuò)展,主要是新的特定HTTP標(biāo)頭:
- 服務(wù)器發(fā)送的事件,服務(wù)器可以將偶爾的消息推送到瀏覽器。
- WebSocket,可以通過升級現(xiàn)有的HTTP連接來設(shè)置的新協(xié)議。
這里可以參考我之前寫的 系統(tǒng)設(shè)計(jì)基礎(chǔ) 長輪詢、WebSocket、服務(wù)器發(fā)送事件(SSEs)協(xié)議
HTTP / 1.0和HTTP / 1.1之間的短鏈接、長連接區(qū)別
在這里插入圖片描述
上圖右邊HTTP1.1通過建立長連接,中間的幾次 TCP握手都省掉了
HTTP管道傳輸和多個(gè)并行連接
由于Keep-Alive標(biāo)頭的行為,HTTP流水線,多個(gè)連接和更多改進(jìn)已得到實(shí)現(xiàn)。
在這里插入圖片描述
HTTP 2.0 更高性能的協(xié)議
多年以來,網(wǎng)頁變得更加復(fù)雜,甚至成為獨(dú)立的應(yīng)用程序。顯示的視覺媒體數(shù)量,增加交互性的腳本的數(shù)量和大小也有所增加:通過明顯更多的HTTP請求傳輸更多的數(shù)據(jù)。HTTP / 1.1連接需要以正確的順序發(fā)送請求。從理論上講,可以使用幾個(gè)并行連接(通常在5到8之間),從而帶來相當(dāng)大的開銷和復(fù)雜性。例如,HTTP管道已成為Web開發(fā)中的一種資源負(fù)擔(dān)。
在2010年代上半年,Google通過實(shí)施實(shí)驗(yàn)性協(xié)議SPDY展示了一種在客戶端和服務(wù)器之間交換數(shù)據(jù)的替代方法。這引起了同時(shí)使用瀏覽器和服務(wù)器的開發(fā)人員的興趣。SPDY定義了響應(yīng)能力的提高,并解決了傳輸數(shù)據(jù)重復(fù)的問題,是HTTP / 2協(xié)議的基礎(chǔ)。
HTTP / 2協(xié)議與HTTP / 1.1版本有幾個(gè)主要區(qū)別:
- 它是二進(jìn)制協(xié)議,而不是文本。不再可以手動讀取和創(chuàng)建它。盡管有這個(gè)障礙,現(xiàn)在仍可以實(shí)施改進(jìn)的優(yōu)化技術(shù)。
- 它是一個(gè)多路復(fù)用協(xié)議??梢栽谕贿B接上處理并行請求,從而消除了HTTP / 1.x協(xié)議的順序和阻塞約束。
- 壓縮頭文件。由于這些請求在一組請求中通常很相似,因此消除了重復(fù)和傳輸數(shù)據(jù)的開銷。
- 它允許服務(wù)器通過稱為服務(wù)器推送的機(jī)制,在需要之前在客戶端緩存中填充數(shù)據(jù)。
請求和響應(yīng)如何并行發(fā)生
上面的照片顯示了請求和響應(yīng)如何并行發(fā)生。還顯示了如何將多個(gè)請求/響應(yīng)拆分為單獨(dú)的幀,并以異步方式一一發(fā)送。
正式標(biāo)準(zhǔn)化后,在2015年5月,HTTP / 2取得了很大的成功。到2016年7月,所有網(wǎng)站有8.7%已在使用它,占所有請求68%以上。高流量的網(wǎng)站采用速度最快,大大節(jié)省了數(shù)據(jù)傳輸開銷和后續(xù)預(yù)算。
由于HTTP / 2不需要適應(yīng)網(wǎng)站和應(yīng)用程序,因此這種快速的采用率很可能是:使用HTTP / 1.1或HTTP / 2對它們是透明的。使用最新的服務(wù)器與最新的瀏覽器進(jìn)行通信就足以啟用它:僅需要有限的一組組即可觸發(fā)采用,并且隨著舊版瀏覽器和服務(wù)器版本的更新,使用量自然增加了,而無需使用其他Web開發(fā)人員的努力。
Http2.0必須建立在TLS的基礎(chǔ)上,也就是必須是Https的請求。
問題
1.http1.1長連接keep-alive和http2.0的多路復(fù)用有什么區(qū)別?
- http1.1 keep-alive 是不關(guān)閉 TCP 連接,也就是長連接;
- 在不使用管道機(jī)制的情況下,交互是單工的,即客戶端必須要等前一個(gè)請求的響應(yīng)返回之后,新的請求才能發(fā)過去。
- 在使用管道機(jī)制的情況下,請求發(fā)送可以非阻塞,但是響應(yīng)返回必須依然嚴(yán)格按照請求的順序。
http2.0多路復(fù)用則是基于流的,那么在傳輸?shù)臅r(shí)候,無論請求還是響應(yīng),只要邏輯上允許就可以傳輸,如果兩個(gè)請求沒有依賴關(guān)系可以不必等待前一個(gè)返回而直接發(fā)送,雖說用的是同一條連接。
2.什么是流水線(管道機(jī)制)?
默認(rèn)情況下,HTTP 請求是按順序發(fā)出的。下一個(gè)請求只有在當(dāng)前請求收到應(yīng)答過后才會被發(fā)出。由于會受到網(wǎng)絡(luò)延遲和帶寬的限制,在下一個(gè)請求被發(fā)送到服務(wù)器之前,可能需要等待很長時(shí)間。
流水線是在同一條長連接上發(fā)出連續(xù)的請求,而不用等待應(yīng)答返回。這樣可以避免連接延遲。理論上講,性能還會因?yàn)閮蓚€(gè) HTTP 請求有可能被打包到一個(gè) TCP 消息包中而得到提升。就算 HTTP 請求不斷的繼續(xù),尺寸會增加,但設(shè)置 TCP 的 MSS(Maximum Segment Size) 選項(xiàng),仍然足夠包含一系列簡單的請求。
并不是所有類型的 HTTP 請求都能用到流水線:只有 idempotent 方式,比如 GET、HEAD、PUT 和 DELETE 能夠被安全的重試:如果有故障發(fā)生時(shí),流水線的內(nèi)容要能被輕易的重試。
今天,所有遵循 HTTP/1.1 的代理和服務(wù)器都應(yīng)該支持流水線,雖然實(shí)際情況中還是有很多限制:一個(gè)很重要的原因是,目前沒有瀏覽器默認(rèn)啟用這個(gè)特性。
問題RFC 2616 中規(guī)定了:
一個(gè)支持持久連接的客戶端可以在一個(gè)連接中發(fā)送多個(gè)請求(不需要等待任意請求的響應(yīng))。收到請求的服務(wù)器必須按照請求收到的順序發(fā)送響應(yīng)。
至于標(biāo)準(zhǔn)為什么這么設(shè)定,我們可以大概推測一個(gè)原因:由于 HTTP/1.1 是個(gè)文本協(xié)議,同時(shí)返回的內(nèi)容也并不能區(qū)分對應(yīng)于哪個(gè)發(fā)送的請求,所以順序必須維持一致。比如你向服務(wù)器發(fā)送了兩個(gè)請求 GET/query?q=A 和 GET/query?q=B,服務(wù)器返回了兩個(gè)結(jié)果,瀏覽器是沒有辦法根據(jù)響應(yīng)結(jié)果來判斷響應(yīng)對應(yīng)于哪一個(gè)請求的。
Pipelining 這種設(shè)想看起來比較美好,但是在實(shí)踐中會出現(xiàn)許多問題:
- 一些代理服務(wù)器不能正確的處理 HTTP Pipelining。
- 正確的流水線實(shí)現(xiàn)是復(fù)雜的。
- Head-of-line Blocking 連接頭阻塞:在建立起一個(gè) TCP 連接之后,假設(shè)客戶端在這個(gè)連接連續(xù)向服務(wù)器發(fā)送了幾個(gè)請求。按照標(biāo)準(zhǔn),服務(wù)器應(yīng)該按照收到請求的順序返回結(jié)果,假設(shè)服務(wù)器在處理首個(gè)請求時(shí)花費(fèi)了大量時(shí)間,那么后面所有的請求都需要等著首個(gè)請求結(jié)束才能響應(yīng)。
所以現(xiàn)代瀏覽器默認(rèn)是不開啟 HTTP Pipelining 的。
由于這些原因,流水線已經(jīng)被更好的算法給代替,如multiplexing多路復(fù)用,已經(jīng)用在 HTTP/2。
HTTP1.X鏈接管理
- 左邊短鏈接
- 中間長連接
- 右邊管道機(jī)制
在這里插入圖片描述
3.現(xiàn)代瀏覽器在與服務(wù)器建立了一個(gè) TCP 連接后是否會在一個(gè) HTTP 請求完成后斷開?
其實(shí)看了上面的內(nèi)容的話就知道答案了,現(xiàn)代瀏覽器默認(rèn)是HTTP1.1協(xié)議,保持長連接是不會斷開的,那么我們來驗(yàn)證下:Chrom瀏覽器F12,2次訪問一個(gè)網(wǎng)站的結(jié)果:第一次:
第二次:
結(jié)果分析:
初始化連接和 SSL 開銷消失了,說明使用的是同一個(gè) TCP 連接
4.一個(gè) TCP 連接可以對應(yīng)幾個(gè) HTTP 請求?
一個(gè) TCP 連接是可以發(fā)送多個(gè) HTTP 請求的。
從問題3的截圖就可以證明了。
5.一個(gè) TCP 連接中 HTTP 請求發(fā)送可以一起發(fā)送么(比如一起發(fā)三個(gè)請求,再三個(gè)響應(yīng)一起接收)?
HTTP/1.1 存在一個(gè)問題,單個(gè) TCP 連接在同一時(shí)刻只能處理一個(gè)請求,意思是說:兩個(gè)請求的生命周期不能重疊,任意兩個(gè) HTTP 請求從開始到結(jié)束的時(shí)間在同一個(gè) TCP 連接里不能重疊。
雖然 HTTP/1.1 規(guī)范中規(guī)定了 Pipelining 來試圖解決這個(gè)問題,但是這個(gè)功能在瀏覽器中默認(rèn)是關(guān)閉的。原因的話問題2已經(jīng)闡述過了,
HTTP2 提供了 Multiplexing 多路傳輸特性,可以在一個(gè) TCP 連接中同時(shí)完成多個(gè) HTTP 請求。
參考:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Evolution_of_HTTP
http://qnimate.com/what-is-multiplexing-in-http2/
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Connection_management_in_HTTP_1.x
https://medium.com/platform-engineer/evolution-of-http-69cfe6531ba0
https://blog.csdn.net/ywlmsm1224811/article/details/96436768