今天是2019年3月12日,是全球資訊網誕生30周年的紀念日,搜尋引擎巨頭谷歌為此在首頁換上了網際網路發明的Logo以此來紀念全球資訊網誕生30周年。
此外,今天早上,著名的開源 Web 伺服器廠商 Nginx 宣布被 F5 收購。我覺得今天可以和大家分享下網際網路的那些歷史。
我們今天之所以可以在網絡上暢遊,都要感謝一個人,他就是被譽為網際網路之父的英國計算機科學家——蒂姆·伯納斯·李。
1980年6月至12月間,伯納斯·李在日內瓦的CERN(歐洲核子研究組織)擔任獨立承包人,在那段時間裡,他提出了一個構想:創建一個以超文本系統為基礎的項目,其目的是方便研究人員分享及更新信息。
Info.cern.ch是世界上第一個網站及網站伺服器,網站在一臺位於CERN的NeXT計算機上運作,於1991年8月6日上線。
伯納斯·李發明的超文本傳輸控制協議,就是我們今天熟悉的 HTTP 協議。目前 HTTP 協議的最新版本是 HTTP/2,HTTP 協議是網際網路的基礎協議——可以說,沒有 HTTP 協議就沒有我們今天的網際網路。
HTTP 協議採用 BS 架構,也就是瀏覽器到伺服器的架構。客戶端通過瀏覽器發送 HTTP 請求給伺服器,伺服器經過解析響應客戶端的請求。
HTTP 是基於 TCP/IP 協議的應用層協議。在 OSI 七層模型中在最上層,它並不涉及數據包(packet)傳輸,主要規定了客戶端和伺服器之間的通信格式,默認使用80埠。
HTTP 協議最早的一個版本是1991年發布的 HTTP/0.9,這個版本只有一個命令,GET。通過 GET 你可以獲取伺服器的資源,比如請求伺服器根目錄下的 index.html 文件。
GET /index.html
伺服器則會返回給客戶端 index.html 的內容,並通過客戶端瀏覽器進行渲染和解析 html 標籤。這個版本的協議規定,伺服器只能回應HTML格式的字符串,不能回應別的格式。也就是說今天的圖像、視頻等多媒體資源在 HTTP/0.9這個版本上是無法進行傳輸的。
<html><body>Hello World</body></html>
1996年5月,HTTP/1.0 版本發布,增加了POST命令和HEAD命令,豐富了瀏覽器與伺服器的互動手段。
這個版本通過HTTP協議任何格式的內容都可以發送,包括傳輸文字,圖像、視頻、文件。這為網際網路的大發展奠定了基礎。
HTTP/1.0 除了增加了請求方法以及對發送文件的支持之外,還增加了格式的改變。除了數據部分,每次通信都必須包括頭信息(HTTP header),用來描述一些元數據。另外還增加了狀態碼、多字符集支持、多部分發送(multi-part type)、權限(authorization)、緩存(cache)、內容編碼(content encoding)等等。
一個正常的 HTTP 請求和響應包括請求的網址、請求方法、狀態碼、HTTP協議版本、請求頭和響應頭。例如下圖所示,請求 Google 的 HTTP 消息頭所示:
在字符的編碼問題上,HTTP/1.0版規定,頭信息必須是 ASCII 碼,後面的數據可以是任何格式。因此,伺服器回應的時候,必須告訴客戶端,數據是什麼格式,這就是Content-Type欄位的作用。
text/htmltext/cssimage/jpegimage/pngimage/svg+xmlaudio/mp4video/mp4application/javascriptapplication/pdf
這些數據類型總稱為MIME type,每個值包括一級類型和二級類型,之間用斜槓分隔。
此外,由於 HTTP/1.0 還可以對數據進行壓縮後傳輸,如下所示即為通過Content-Encoding欄位說明數據的壓縮方法,表示使用 gzip 壓縮數據:
Content-Encoding: gzip
HTTP/1.0 版也並不是完美的,它的主要缺點是,每一次建立TCP連接只能發送一個請求。發送數據完畢,連接就關閉,如果還要請求其他資源,就必須再新建一個連接。如果多次請求,勢必就會造成頻繁的對伺服器進行請求而對伺服器產生較大的資源損耗。
為了解決這個問題,有些瀏覽器在請求時,用了一個非標準的Connection欄位。
Connection: keep-alive
這個欄位要求伺服器不要關閉TCP連接,以便其他請求復用。伺服器同樣回應這個欄位。但是這個並不是一個統一的標準。
1997年1月,HTTP/1.1 版本發布,這個版本只比 1.0 版本晚了半年。它進一步完善了 HTTP 協議,一直用到了今天,直到現在還是最流行的版本。
這個版本最大的變化就是將持久化連接加入了 HTTP 標準,即TCP連接默認不關閉,可以被多個請求復用,不用聲明Connection: keep-alive。客戶端和伺服器發現對方一段時間沒有活動,就可以主動關閉連接。不過,規範的做法是,客戶端在最後一個請求時,發送Connection: close,明確要求伺服器關閉TCP連接。此外,HTTP/1.1版還新增了許多方法,例如:PUT、PATCH、HEAD、 OPTIONS、DELETE。另外,客戶端請求的頭信息新增了Host欄位,Content-Length 欄位、管道機制等新特性。
HTTP1.1版雖然允許復用TCP連接,但是同一個TCP連接裡面,所有的數據通信是按次序進行的。伺服器只有處理完一個回應,才會進行下一個回應。要是前面的回應特別慢,後面就會有許多請求排隊等著。這稱為隊頭堵塞。
為了解決這個問題,2009年,谷歌公開了自行研發的 SPDY 協議,這個協議在Chrome瀏覽器上證明可行以後,就被當作 HTTP/2 的基礎,主要特性都在 HTTP/2 之中得到繼承。
2015年,HTTP/2 發布。它不叫 HTTP/2.0,是因為標準委員會不打算再發布子版本了。HTTP/2 增加了二進位分幀、多路復用、伺服器推送(server push)、頭部壓縮等特性。
HTTP/2 採用二進位格式傳輸數據,而非 HTTP 1.x 的文本格式,二進位協議解析起來更高效。 HTTP / 1 的請求和響應報文,都是由起始行,首部和實體正文(可選)組成,各部分之間以文本換行符分隔。HTTP/2 將請求和響應數據分割為更小的幀,並且它們採用二進位編碼。
多路復用,代替原來的序列和阻塞機制。所有請求都是通過一個 TCP連接並發完成。HTTP 1.x 中,如果想並發多個請求,必須使用多個 TCP 連結,且瀏覽器為了控制資源,還會對單個域名有 6-8個的TCP連結請求限制。
在 HTTP/2 中,有了二進位分幀之後,HTTP /2 不再依賴 TCP 連結去實現多流並行了,在 HTTP/2中:
同域名下所有通信都在單個連接上完成;單個連接可以承載任意數量的雙向數據流;數據流以消息的形式發送,而消息又由一個或多個幀組成,多個幀之間可以亂序發送,因為根據幀首部的流標識可以重新組裝。
這一特性,使性能有了極大提升:
同個域名只需要佔用一個 TCP 連接,消除了因多個 TCP 連接而帶來的延時和內存消耗;單個連接上可以並行交錯的請求和響應,之間互不幹擾;在HTTP/2中,每個請求都可以帶一個31bit的優先值,0表示最高優先級, 數值越大優先級越低。有了這個優先值,客戶端和伺服器就可以在處理不同的流時採取不同的策略,以最優的方式發送流、消息和幀。
服務端可以在發送頁面HTML時主動推送其它資源,而不用等到瀏覽器解析到相應位置,發起請求再響應。例如服務端可以主動把JS和CSS文件推送給客戶端,而不需要客戶端解析HTML時再發送這些請求。
服務端可以主動推送,客戶端也有權利選擇是否接收。如果服務端推送的資源已經被瀏覽器緩存過,瀏覽器可以通過發送RST_STREAM幀來拒收。主動推送也遵守同源策略,伺服器不會隨便推送第三方資源給客戶端。
HTTP/3 是即將到來的第三個主要版本的HTTP協議。
在HTTP/3中,將棄用TCP協議,改為使用基於UDP協議的QUIC協議實現。QUIC 協議是 google 開發的一套協議,IETF 中的 QUIC 工作組致力於創建 QUIC 傳輸協議。 QUIC 是基於 UDP 實現的協議,是用來替換 TCP 的。QUIC 協議最初是由Google發起的項目,後面慢慢成為了 HTTP/2-encrypted-over-UDP 協議。