萬維網:蒂姆·伯納斯·李的資訊帝國

資訊大爆炸

人類文明史就是一部資訊史——人類如何獲取、存儲和傳遞資訊的歷史

遠古時代,人類主要通過觀察自然現象來獲取資訊和知識,通過口口相傳的方式傳遞資訊。

而後,人類發明了結繩、符號,可以將個人大腦中的資訊加以符號化——這可以說是人類最早的資訊存儲形式(它也是一種傳播形式)。這些符號不斷地傳播並豐富,最終演化為文字。

文字是個偉大的發明,它使得資訊和知識能夠跨越時空傳遞。如果沒有文字,人類文明只能以「代代相傳」的方式進行。

除了口口相傳和文字,人類還發明了諸如烽火、燈塔、鼓聲等遠距離通訊手段——人類對通訊距離的不斷突破,到近代發明電報、無線電後,達到了一次高峰。

人類生產資訊的腳步也是不斷加快。歐洲和中國在古希臘和春秋戰國時期出現了一次資訊生產高峰,古希臘時期建造出了世界上最早的圖書館之一——亞歷山大圖書館。

圖書館是人類進行集中式資訊管理的偉大嘗試

歐洲文藝復興和啟蒙運動時期是人類資訊生產的另一個高峰。如果說在古希臘時期,知識生產大分工只是處於萌芽階段的話(那時候哲學和科學是不分家的),文藝復興和啟蒙運動時期則正式開啟了知識生產大分工的大門。科學從哲學中獨立出來,逐步發展成今天所理解的物理學、化學、生物學、經濟學等學科。

知識生產大分工的結果是人類進入了知識生產的指數加速時代。人類現在幾十年生產出來的知識比過去一千年都要多。

過去,中國古人只需要背熟四書五經大學中庸就行了,現在光一門物理學(或者任意其他一門學科)的知識量就比那些多得多。古人可以做到「無所不知」,而二十世紀後的人類已經不可能做到這一點了——甚至不可能做到窮盡一門學科的知識。

人類知識量指數增長帶來的是資訊管理問題。面對資訊海洋(知識是一種資訊),人們不知道該獲取哪些資訊了,需要某類資訊的時候也不知道該去哪裡獲取了。人類面臨著資訊失控的危險。

人們可以建造更大的圖書館——再大也裝不下所有的知識,而且圖書館規模越大,可能越難快速檢索到有用的資訊。

人們還嘗試編纂百科全書——將那些重要的知識集中到一系列書籍中,為普通大眾在知識的海洋中提供指南和導航。中國明朝永樂年間編纂了集大成之類書《永樂大典》;啟蒙運動時期法國哲學家丹尼·狄德羅編纂了歐洲第一部大百科全書;1768 年英國人編纂了著名的《不列顛百科全書》。

百科全書同樣不可能囊括所有的知識。

萬尼瓦爾·布希與 MEMEX

電腦並不是被設計用來處理資訊的

這從電腦的名字就能看出來——Computer 原意是「計算員」,在電腦出現之前是一個專門的職業(像美國的人口普查、歐洲的航海曆之前都是由這些人類計算員手工算出來的)。

從巴貝奇的差分機和分析機,到何樂禮的電動製表機,到萬尼瓦爾·布希的微分分析儀,到第一台通用電子電腦 ENIAC,其設計的目的無不是為了數值計算。

馮·諾依曼當初「鬼使神差」地加入莫爾學院的 ENIAC 工作小組,原因也在於尋求用電腦計算原子彈核爆問題——這一加入讓他「鬼使神差」地成了現代電腦之父。

隨著二戰結束,電腦逐漸從軍事和科研走向商業領域。

同時人們嘗試進一步挖掘電腦的計算潛力。根據圖靈的理論,通用電腦可以計算所有的可計算問題,可以無限逼近(甚至超越)人腦——這些研究我們今天叫「人工智慧」,圖靈也被公認為人工智慧之父。

然而,還存在另一派研究人員,他們認為電腦研究應該要為提升人類工作效率服務,而不是當前看不到實際用途的所謂的「人工智慧」。

他們發現,人們在工作中通常只有 15% 的時間在「思考」,其餘時間都在查閱資料、繪製圖表等,工作效率非常底下。他們希望能用電腦來處理這些低級而耗時的事務,將人類的大腦解放出來去思考更有價值的事情。

總之,這些人開始研究用電腦處理資訊——這些研究最終推動人類文明走向資訊化時代。

數值處理和資訊處理是不同的。

數值處理關注如何求三角函數、對數、微積分等數學計算問題,主要用在軍事、科研以及商業報表領域。

資訊處理關注人類社會的各種資訊,諸如書籍、信函、圖片、音頻、影片。

第一台通用電子電腦 ENIAC 全稱是 Electronic Numerical Integrator And Computer,翻譯過來是「電子數字積分電腦」——看名字就知道人們想用它來幹嘛。

電腦的兩大分支:數值處理和資訊處理,在不同時期存在不同的發展態勢。二戰時,主要用來做數值處理(ENIAC 的目的是計算彈道);戰後其重心逐步轉變為資訊處理上(當然不是說數值處理方面就沒有發展了),最終推動人類走向資訊化時代;如今,人工智慧被重新提上議程,自動駕駛、智慧城市甚是火熱。

前面說隨著人類資訊量的指數增長,傳統的資訊存儲和檢索方式面臨越來越大的挑戰。

首先是存儲。傳統的資訊存儲方式主要是書籍、文件這些紙質媒介,這種媒介在資訊量驟增的二十世紀已經相當笨重和效率低下。大學需要建造龐大的圖書館,公司需要準備大量的文件櫃(不可避免地佔用大量空間)歸檔各種函件。

其次是檢索。雖然有各種文件歸檔方案,在海量文件中找到想要的那個仍然是一件非常費力而又無聊的事情——一旦記不清文件放在何處更是讓人抓狂。

所以人們想能否通過電腦來解決這些問題。

1945 年,萬尼瓦爾·布希(Vannevar Bush)發表了一篇名為”As We May Think”的文章。文章描述了一種被稱為 MEMEX 的機器,實現新型的數字化的資訊存儲和檢索模式。

MEMEX 設備相當於一個數字圖書館,它將現實中的各種書籍、圖片、文件等數字化並存儲在微縮膠片上,解決紙質媒介的存儲效率問題。

MEMEX有一個螢幕,資料可以投影到上面進行閱讀,還有一個鍵盤,一系列按鈕和把手。

更重要的,布希在這篇文章中提出了後來被稱為「超文本」的概念,兩個相關聯的文檔之間可以建立某種關聯使得可以從一篇文檔直接跳轉到另一篇文檔。

布希並沒有在他的文章中使用「超文本」這個詞,超文本(Hypertext)一詞是德特·納爾遜於 20 世紀 60 年代創造的。

超文本在今天看來稀疏平常,但在布希那個年代是一個非常大膽的、創新的設想。傳統的資訊檢索是集中式檢索。想想我們在圖書館看書,在一本書裡面看到對另一本書的引用,此時如果我們需要看被引用的那本書,就得在圖書館裡面到處找。再想想我們在 Linux 命令行查看某命令的幫助文檔,當我們看到 See also 後像去看其引用的命令的細節,我們得退出去然後 man 另一個命令。這種檢索模式稱為「線性檢索」。

和傳統的線性檢索方式不同,超文本允許任何資訊之間交叉引用,可以從一個文檔直接轉移到另一個文檔,且能方便地返回到源文檔。

超文本的顛覆性在於它改變了人類幾千年來的集中式樹形目錄的資訊檢索方式

超文本的概念催生了後來的萬維網。

電子郵件與阿帕網

上世紀 60 年代,電腦資源是非常昂貴的,人們就想能否將這些昂貴的電腦通過某種方式連接起來,用戶可以在一台電腦上直接使用另一台電腦資源,從而分攤計算和存儲成本。

1963 年,美國國防部的高級研究計劃局啟動了「阿帕網」(Advanced Research Projects Agency Network,高級研究計劃局網,簡稱 ARPANET)項目——通過將計劃局的所有電腦系統連接在一起,用戶就能使用網路上的任何電腦設施。

阿帕網使用了存儲轉發分組交換的數據交換模式,該模式沿用至今。

存儲轉發是用來解決電腦之間的連接問題。研究員們為如何將眾多的電腦兩兩連接起來犯難。不太可能為每兩台電腦都拉一根網線——那樣網線數量將很快變得不可控。研究員們借鑒了電報行業的做法。

19 世紀電報行業在英國飛速發展,各大城市設有眾多的電報網點。電報公司之間、以及各大城市之間如何通訊成為必須解決的問題。英國在幾個主要城市設立了交換中心。電報公司之間、城市之間無需兩兩相連,大家可通過交換中心轉發電報。

交換中心內部有兩撥人員,第一撥人將發送方的電報內容記錄下來,由另一撥人通過合適的出口電報機轉發給目的地(或下一個交換中心)。

將電報記錄在案的好處是它可以充當存儲系統,如果下一個交換中心很忙,則可以將報文暫存起來,等線路空閑時再發。

這就是所謂的「存儲轉發」。

通過交換中心轉發消息,使得電腦之間無需兩兩相連;通過存儲(緩衝隊列),讓上游不會因下游繁忙而阻塞(另外在分組交換模式下,交換機是先將收到的 bit 存儲起來,直到接收到完整的分組後才會轉發)。

當然存儲轉發不是沒有缺點的,報文在到達目的地之前,需要經過多個交換中心(交換機)的存儲和拷貝,大大增加了時延。

分組交換用來解決佔線問題。如果我們一次發送整個報文(可能很大),那麼一方面會導致高速通訊線路在一段時間內被某個用戶獨佔;另外採用存儲轉發策略的交換中心需要先存儲整個報文,這會帶來巨大的存儲開銷;最後,如果消息傳送失敗,需要重傳整條報文(而不是失敗的那部分)。

所以,人們決定將整個報文切分成一個個更小的分組(Package),以分組為單位在網路上傳輸。這樣高速線路就不會被某一個用戶的龐大消息獨佔了,交換中心需要存的東西也小很多。

分組交換也不是沒有缺點的。分割成多個分組後,每個分組都必須攜帶額外元數據(首部),增加了傳輸的比特數。另外接收端也必須將分組重組成報文(消息)。

最初接入阿帕網的只是高級研究計劃局內部的電腦。很快,加利福利亞大學、猶他大學、斯坦福研究院等跟計劃局有合作關係的大學電腦也加入到該網路。在大學校園裡,一些研究生和程式設計師也開始將自己的主機接入其中,很快便在校園內形成一種獨特的網路社區文化。

到 1971 年春,共有23 台主機聯網。

1972 年,阿帕網新負責人羅伯茨在首屆國際電腦通訊大會上組織了一次公開演示,向世人展示阿帕網。這次演示影響很大,越來越多的研究機構和大學開始接入阿帕網,一年後,網路中的主機數量達到 45 台。

4 年後,數字升到 111 台。

從數量看,增長非常緩慢。

真正推動阿帕網發展的是電子郵件

阿帕網最初並沒有考慮電子郵件。

1971 年,BBN 的兩位程式設計師為阿帕網開發了實驗性的電子郵件系統——起初他們並不認為這玩意能成什麼氣候。

然而很快,電子郵件成為阿帕網中最大的流量,郵件註冊用戶導 1975 年已過千人。收發電子郵件的需求也成為推動第一批非阿帕網網路發展的主要力量

電腦服務商看到了電子郵件的商業價值。很多服務商開始搭建自己的電腦網路(大多數是基於阿帕網的技術)提供電子郵件服務,形成了 70 年代的「電子郵件大戰」。

電子郵件推動了電腦網路的發展,催生了大量基於阿帕網技術實現的、相互獨立的電腦網路。

一個問題是,這些網路之間無法通訊(自然也無法收發郵件)。

於是人們開始考慮網際互聯問題。

當時阿帕網使用的網路協議叫 NCP(Network Control Protocol,網路控制協議),該協議存在諸多缺陷,其中一個問題是 NCP 僅能用於同構環境中(所有電腦都要運行相同的系統)。

人們決定開發個支援異構系統的新協議替代 NCP。

1973 年,高級研究計劃局的研究員羅伯特·卡恩和溫頓·瑟夫著手設計 TCP/IP 協議;1980年,用於「異構」網路環境的 TCP/IP 協議研製成功;1982年,ARPANET開始採用TCP/IP協議替代 NCP 協議。

TCP/IP 協議的出現推動了電腦網路之間的網際互聯(也就是我們今天說的互聯網),最終催生出世界上最重要的互聯網——網際網路。

個人電腦與網際網路

電子郵件推動了阿帕網的發展,並在商業公司的推動下形成各種電腦網路百花齊放的局面,而這種局面最終因網際互聯的實際訴求而催生出網際網路。

但網際網路起初增長速度是很慢的,到 1984 年接入的主機數量也不過千台,主要是大學、科研和一些商業機構。

真正推動網際網路快速發展的,是個人電腦浪潮

80 年代,個人電腦風起雲湧,IBM、蘋果、微軟群雄逐鹿,軟硬體百花齊放,個人電腦逐步成為大眾普遍接受的電子消費品和辦公品。

大量個人電腦開始接入網際網路,人們不但在網上用電子郵件交流,還開始交流整篇文檔。

很快,網際網路上產生了大量沒有目錄組織的文檔——如何組織和檢索這些文檔成為一個亟待解決的問題

人們開發了一些目錄服務軟體來解決文檔檢索問題。比如有一款叫「阿奇」的軟體,通過梳理網際網路,創建一個包含所有可供下載文件的目錄,用戶直接在該軟體裡面即可下載,無需關注文檔的具體位置。有些軟體還提供了根據文檔名稱模糊模糊檢索功能。

和我們今天在瀏覽器中直接點「下載」按鈕就能下載文檔不同,那個時候人們要下載某個文檔,必須先知道該文檔的精確位置。典型的操作流程如下:

  1. 張三先通過 ftp 登錄到某台遠程主機上;

  2. 登錄上去後,進入到某個目錄;

  3. 從那個目錄下載文件;

也就是說,張三必須知道文檔所在的主機,而且能登錄這台主機,然後要進入到相應目錄。

張三不可能知道網際網路上所有文檔的精確位置。所以說,當時這種目錄服務軟體還是較好地解決了人們的痛點。

這些軟體的目錄組織形式和傳統書籍無異,也是採用集中式樹形結構目錄,文檔之間沒有直接的關係。假如用戶在一篇文檔中看到「查爾斯·巴貝奇」的名字,他想檢索查爾斯·巴貝奇的資訊,就要回到目錄重新查找——他無法從當前文檔直接進入關於查爾斯·巴貝奇生平的另一篇文檔。

上面提過,早在 40 年前,萬尼瓦爾·布希就提出了超文本的概念來解決資訊交叉檢索問題。

那麼,能否將超文本和網際網路結合起來呢?

蒂姆·伯納斯·李與萬維網

在今天看來,網際網路和超文本好像天然就是在一起的,然而在上個世紀八十年代卻不是這樣。那時候超文本和網際網路都是很熱門的話題(至少在學術界如此),而且超文本也開始應用於一些 CD-ROM 百科全書等消費類產品,然而,兩者是單獨發展的,沒有人真正想到能將超文本應用在網際網路上。

有個叫蒂姆·伯納斯·李的英國軟體工程師最終想到了這點,他於 1989 年向歐洲核子研究中心(CERN)遞交了一份項目提案,在這份提案中,描述了今後稱為「萬維網」的雛形。

歐洲核子研究中心是在聯合國教科文組織的倡導下,由歐洲 11 個國家於 1954 年 9 月創立。作為一個國際性組織,擁有非常複雜的人員和組織結構,研究項目眾多、人員變動頻繁。在這樣一個大型組織中,如何高效地組織和檢索資訊(人物資訊、項目資訊、各種技術檔案等)成為一個棘手的問題。

人們經常被諸如下面的問題困擾:

  • 這個模組在哪裡用到了?

  • 這些程式碼是誰寫的?在哪裡執行?

  • 哪些系統依賴該設備?

另外,CERN 的人員流動很大,經常因為人員離職而導致關鍵資訊丟失——多數情況下不是因為離職人員沒有存留文檔,而是因為後面的人找不到文檔了。

CERN 面臨著嚴重的資訊丟失問題。

伯納斯·李進一步補充道:「在不久的將來,世界其他國家和組織也會面臨同樣的問題」。

所以,必須有一套通用的資訊管理方案。

當時人們普遍使用樹形結構來組織資訊。Unix 文件系統就是一個例子。當時 CERN 正在用的 CERNDOC 文檔系統也是。在這種系統中,如果一個文檔(樹的葉子節點)中引用了另一個文檔(另一個葉子節點,如我們 man 查看命令文檔時的 See also),你是無法直接打開被引用的那篇文檔的,你必須先退出當前文檔,然後從目錄開始重新檢索被引用的那篇文檔。

樹形結構並沒有表達資訊之間的真實關係。比如有一篇講差分機的文章,裡面提到了查爾斯·巴貝奇,該場景中,「差分機」和「查爾斯·巴貝奇」是有關聯的兩條資訊,但在集中式樹形目錄中,這兩條資訊是作為單獨的、毫無關聯的實體存在的,我們從目錄中看不出「差分機」和「查爾斯·巴貝奇」存在任何關聯。

在傳統的基於目錄的資訊組織和檢索方式中,我們基本上只是管理了一個個孤零零的資訊本身,並沒有管理資訊之間的關係。

相較於樹形目錄,交叉檢索的超文本更能反映現實世界的資訊組織結構,它允許人們從一條資訊體直接跳轉到與之關聯的另一條資訊體,而無需重新檢索目錄,這大大提高了資訊的檢索效率。

超文本的概念人們四十年前就提出了,在 80 年代已經有一些實際應用,如果僅僅到此為止,伯納斯·李的這個提案也沒有什麼出眾之處——不過是開發另一款超文本資訊管理系統而已。

這份提案的創新之處在於,它所描繪的超文本系統並不是一個系統,而是全球範圍的系統集群

伯納斯·李發現,如今全球已經面臨著資訊大爆炸帶來的資訊管理問題:人們不知道該去哪裡找到有用的資訊;組織機構每天都面臨著大量的資訊丟失;用集中式目錄管理海量資訊力不從心。

另一方面,雖然當時已經開發出一些超文本系統,但這些系統自成一體,相互之間無法實現資訊互聯互通。A 系統的超文本只能鏈接到 A 系統內部的文檔,無法引用 B 系統的文檔;無論是 A 系統還是 B 系統,都無法囊括世界上所有的資訊。

伯納斯·李的設想是,能否將全世界所有的系統看做一個整體的、巨大的、動態的資訊存儲庫,通過超文本將這些資訊連接起來?

讓超文本跨越系統邊界的限制,在地球上構成一個龐大的資訊宇宙空間,這是個大膽的設想。

這個設想在當時看並非不可實現。網際網路已經打破網路邊界,能夠將全世界的電腦連接成一個整體。

那麼,讓超文本插上網際網路的翅膀不就能夠馳騁於系統之間了嗎?

伯納斯·李將這個基於網際網路的超文本資訊管理系統稱為萬維網(World Wide Web)。

萬維網的關鍵組件

URI:

由於資訊分布在世界各地,首先的問題便是如何找到這些資訊?

在萬維網中,所有的資訊統一稱為資源。每個資源都有唯一的名字(或者叫標識)。為了讓全世界各種系統都能夠理解這些名字,資源的命名必須符合某些規範——這個規範叫統一資源標識符(Uniform Resource Identifier,簡稱 URI)。

現在萬維網基本都是用 URL(Uniform Resource Locator,統一資源定位符) 這種 URI 方案。

完整的 URL 長這樣:

<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>

不過我們在 HTTP 協議應用中很少用到 user、password 和 params,所以看起來長這樣:

<scheme>://<host>:<port>/<path>?<query>#<frag>

這個 URL 格式告訴客戶端如何找尋並使用資源。scheme 告訴客戶端和伺服器端(包括代理)如何解析 URL以及如何處理資源(如通過 HTTP、FTP、SMTP 等協議)。 host 說明資源在哪台主機,port 說明由該主機上哪個埠進程來接收並處理客戶端的請求。path 指定資源在該主機上具體什麼位置。如果說 host 相當於公司總機號,那麼 path 則相當於分機號。frag 說明客戶端只關注整個資源的某個片段(注意該參數只對客戶端程式有效,不會傳給伺服器,伺服器總是返回完整的資源給客戶端)。

URL 的問題是它和資源的具體位置密切綁定,一旦資源位置變了(如換域名了,或者存放位置變了),原來的 URL 也就失效了。這相當於你的身份證只能在本省使用,出省就得換身份證。

URL 的另一個問題是不好記。URL 對美國以外的人(特別是使用表意文字的人群)不太友好。萬維網的一個設計原則是最大兼容性,為了實現這一點,URL 標準規定 URL 只能使用 7 位編碼方案的 ASCII 字元,這樣便能最大程度兼容現有的協議(如 SMTP 協議),超過 7 位的字元都會被轉義。另外,隨著資源的爆炸式增長,URL 變得越來越長。

所以人們還制定了另一種 URI 方案叫 URN(Uniform Resource Name,統一資源名),這是真正的名字(相較而言,URL 是資源的位置而不是名字),它不會隨著資源的位置變化而變化。

URN 雖然看起來更高大上,但很難普及(至少在目前以及不遠的將來)。從其目標來看(資源不會隨著位置變化而變化),就目前的網際網路現狀來說,需要某種中轉設施(或叫註冊中心)去做名稱和位置的映射(類似 DNS 服務做域名到 IP 的映射),而且要將現存的大量的 URL 轉換成 URN,這是個浩大的工程,許多萬維網基礎設施需要改變。

另一方面,資源位置改變後,人們可以通過 CNAME、rewrite、HTTP 重定向等手段實現新舊 URL 的轉發,甚至對於很多 URL 來說,服務提供者可以簡單粗暴地直接廢棄也不會造成多大影響。所以對於很多公司來說,這可能並不是個急需解決的問題。

隨著網址導航網站特別是搜索引擎出現後,URL 的第二個問題(難以記憶)的問題也隨之解決了——現今人們很少直接拿 URL 去訪問網站了。

所以到目前為止,URL 的日子過得還挺滋潤的。

MIME:

客戶端定位並拿到資源後,它如何處理或使用這些資源呢?客戶端如何知道伺服器返回的是圖片還是普通文本呢?

萬維網將一切都視為資源,而且還給這些資源分門別類——但這其實不是萬維網自己的創舉。早在電子郵件時代,人們為了在電子郵件中收發多媒體資源(而不僅僅是純文本),就發明了 MIME 媒體類型(Multipurpose Internet Mail Extensions,多用途互聯網郵件擴展類型),萬維網採納了該類型標準。

MIME 媒體類型採用兩層分類結構:主類型+子類型,用 / 分割。有時候可能還要帶上一些額外參數說明細節。

例如 HTTP 協議中我們常見的幾種類型:

Content-Type: text/html // html 純文本
Content-Type: text/plain // 純文本
Content-Type: image/jpeg // jpeg 格式圖片
Content-Type: video/quicktime // quicktime 格式音頻
Content-Type: application/json // json 格式數據

在 HTML 表單中我們還見過一種複合表單類型:

Content-Type: multipart/form-data;boundary=AauYd8a

它表示我們提交的表單內容由多種媒體類型組成。比如在註冊時,我們要填寫用戶基本資訊,還要上傳頭像,這裡就存在 text/plain 和 image/jpeg 兩種媒體類型,所以此時我們得用 multipart/form-data 來表示該 HTTP 主體是個複合類型,然後在主體中將每個類型內容都帶過去,這些類型的內容之間通過 boundary 分割(此處就是字元串 AauYd8a)。

我們用 postman 模擬註冊請求,填寫了兩個欄位:欄位 name 是姓名,普通文本;欄位 avatar 是頭像,png 圖片。得到的 HTTP 請求報文如下:

image-20220413155054881

本報文主體是由 text/plain 和 image/png 兩種媒體類型組成的複合媒體類型,兩者之間通過 HTTP 首部指定的 boundary 分割。

當然複合媒體內部還可以再放複合媒體,比如上圖中第二部分我們可以再由音頻和影片複合,然後由本部分首部指定新的 boundary 來分割音頻和影片內容的分隔符。

目前存在幾千個 MIME 類型,完整的類型列表可在 IANA 官網查看。

客戶端拿到資源並知道了資源類型後,如果客戶端能夠編解碼此種類型,便能夠正確處理並顯示。現今瀏覽器一般都能支援幾百種常見類型處理,而且可以通過安裝擴展(或者調起本地軟體)支援更多的媒體類型。

HTTP:

雖然 URI 本身並不限制方案(scheme),但要想將全世界的電腦組織成一個龐大的統一的超文本系統,則必須使用統一的數據傳輸協議——這個協議就叫 HTTP。

如果說萬維網是一個資訊帝國,那麼 HTTP 就是這個帝國的官方語言

HTTP 協議的核心功能是讓客戶端能夠告訴伺服器端它想要對資源進行做什麼操作——這個能力體現在 HTTP 請求報文的起始行,如:

GET /doc.html HTTP/1.1
......

這個起始行包括三部分:操作、資源、協議版本。

HTTP 的一個創舉是將種類繁多的、亂七八糟的操作高度抽象成幾個動詞。在第一版(HTTP/0.9)中,由於人們只需要查看資源,所以只有 GET 這一個動詞。後續版本加入了 HEAD、PUT、POST、TRACE、OPTIONS、DELETE 等動詞(動詞是可擴展的)。

說下幾個常用的:

  • GET:最常用的方法,請求獲取某個資源;

  • HEAD:和 GET 類似,不過伺服器只返回首部而不返回主體(Body),在客戶端不需要主體資訊的時候(如僅想查看資源的元資訊)能節約頻寬;

  • PUT:如其名,客戶端向伺服器寫入(put)文檔(和 GET 的行為相反,類似於我們用 FTP 上傳文件)。PUT 的標準行為是用客戶端請求報文的主體內容覆蓋伺服器上的整個資源(如果資源不存在,則創建);

  • POST:向伺服器」輸入「數據。有時候我們並不是想創建一個新資源,而僅僅是修改或增刪該資源的一些屬性,就可以用 POST 將相關數據提交給伺服器。和 PUT 不同,POST 的具體行為由伺服器端決定(而 PUT 的語義已經包含了其行為);

  • DELETE:如其名,刪除資源。刪除操作的語義是確定的,但伺服器端可以拒絕執行該操作(拒絕刪除某資源,或者僅僅是做資源歸檔)。

起始行的第二部分是資源。這裡一般是寫本地資源路徑(在使用代理時也可能寫絕對 URL)。

第三部分說明客戶端支援的 HTTP 協議的最高版本,伺服器端可據此決定返回的數據格式(如有些低版本協議客戶端不支援某些新特性)。

相應地,伺服器端需響應處理結果——這個也是體現在 HTTP 響應報文的起始行,如:

HTTP/1.1 200 OK

也是由三部分構成:協議版本、處理結果狀態碼、結果描述。

HTTP 的狀態碼分成五大類:

  • 100 ~ 199:資訊性狀態碼,平時見到最多的可能是 101 Switching Protocols,協議升級(如 WebSocket 中就用到);
  • 200 ~ 299:成功狀態碼,說明伺服器端成功執行了客戶端的請求;
  • 300 ~ 399:重定向狀態碼,說明要到其他地方查找資源;
  • 400 ~ 499:客戶端錯誤,如未授權、請求的資源不存在;
  • 500 ~ 599:伺服器端錯誤,如經常遇到的 502 Bad Gateway;

HTTP 報文的第二大塊是首部。首部提供應用程式和資源的元資訊,如客戶端支援的媒體類型列表、主體的媒體類型、主體長度、快取策略等。

HTTP 首部有兩個特點(這裡說的是 HTTP/1.X):

  1. 純文本;
  2. 可擴展;

我們有時會聽說 HTTP 是純文本協議,這不是說 HTTP 只能傳輸純文本(HTTP 能夠傳輸圖片、影片等所有類型數據),而是說 HTTP 的首部是 ASCII 純文本的。比如下面的請求首部:

GET / HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
......

我們能看出它是在講人話。首部是 key: value 格式的文本表示。

相應地,什麼是二進位協議呢?像 IP、TCP、DNS 協議的首部那樣,採用二進位位來表示特定含義的協議,這些協議的首部往往也是固定的。

純文本首部的缺點是效率低,文本顯然比二進位形式更占空間,比如”Cache-Control:no-cache”佔了 22 位元組,但在二進位協議中可能只需要 4 個比特就能搞定。另外報文接收方需分割字元串首部後進行字元串比較,其效率也遠低於位操作。

但純文本首部的一大優點是擴展性很好。二進位協議一般都是固定長度首部(如 TCP、DNS),所能表達的資訊有限。純文本首部一方面可以隨意增加新首部,另外對現有首部的值也可以隨意擴展——可擴展性是 HTTP 協議的一個重要原則。

這裡說的是 HTTP/1。HTTP/2 是二進位協議,採用 frame 作為傳輸單元。

HTTP 報文的第三大塊是主體。主體可以是任何文本或二進位數據,HTTP 協議通過一系列首部提供了主體的相關資訊,如 Content-Type 指定主體的 MIME 類型,Content-Length 指定主體的長度,Content-Encoding 指定主體的編碼方式(如 gzip 壓縮)。

早期 HTTP 並沒有 Content-Length 首部,客戶端是通過伺服器端關閉連接來感知主體傳輸完畢,但有一個問題:客戶端無法知道該連接是否正常關閉的(有可能伺服器端除了問題,數據發送一半的時候宕掉了)。所以後面加了 Content-Length 首部。該首部在持久連接場景下是必須的——此場景伺服器端發送完報文後不會關閉 TCP 連接。

從上面三大塊我們發現,可擴展性是 HTTP 協議的一個核心設計原則。靈活的擴展能力一方面滿足了萬維網上千姿百態的資源和資源使用方式,另外也使得 HTTP 協議自身擁有良好的向後兼容性(HTTP 協議還專門有個狀態碼 101 表示協議版本協商)。

B/S 架構:

萬維網相較於傳統超文本系統的一大特點是存儲和展示分離

萬維網的資源是分散式存儲的,存儲系統(分布在世界各地的電腦)之間採用的作業系統、軟體以及協議各不相同,這要求資源的展示不能依賴於存儲實現細節。

萬維網採取了瀏覽器/伺服器架構(B/S 架構。這裡說的瀏覽器是泛指實現了萬維網相關協議,能夠正確展示各種資源的終端程式)。瀏覽器負責展示資源,伺服器負責存儲資源。瀏覽器不關心伺服器如何處理和存儲資源,伺服器只需要做兩件事情:首先,給資源取個名字(URI)並公布出來;然後,伺服器將資源以合適的方式(HTTP 協議)提供給瀏覽器——如此,瀏覽器便能正確地獲取並展示該資源。

12333

資源的展示和存儲分離在今天看來稀疏平常,其實它是一個非凡的創舉。當時在大部分系統中,資訊的展示是依賴於存儲格式的,一種系統中的資訊無法在另一種系統正常顯示(就好比無法在 PDF 閱讀器中打開 excel 格式文件一樣)——或者說,特定格式的資訊資源必須用對應的應用程式打開。

伯納斯·李提出「瀏覽器」的概念——它是一款不關心資源存儲而只專註於資源展示的軟體。因為我們對瀏覽器過於熟悉,可能並不會被這個概念激起多少波瀾,我們不妨換個名稱叫「通用資訊閱覽器」。什麼意思呢?這個應用程式並不是只能打開某一種類型的資源,它(理論上)可以打開任何類型資源——這才是「資源的展示不依賴於存儲格式」的終極理念。

當然,現實中沒有哪一款瀏覽器能支援所有 MIME 媒體類型,所以存在類型協商。具體做法是瀏覽器在 HTTP 請求報文中通過 Accept 首部告訴伺服器它能夠(或說希望)接收的媒體類型有哪些;伺服器則在響應報文首部通過 Content-Type 告知瀏覽器自己返回的資源具體是什麼媒體類型(這不代表伺服器端一定是以該類型存儲資源的,參見後面「網關」一節的說明),如此,如果瀏覽器支援該媒體類型,則能夠正常解析與展示。

也就是說,只要伺服器端返回的資源格式是瀏覽器支援的 MIME 類型,瀏覽器就一定能夠正確展示(而不管該資源在伺服器端是怎麼存儲的)。

如此,我們在終端上只需要安裝一個瀏覽器(而無需像過去那樣安裝上百個專用軟體)就能瀏覽互聯網上各種形式的資訊。

這種架構使得瀏覽器成為萬維網的入口,瀏覽器因此成為各公司和創業者的爭奪焦點,在 90 年代掀起一場瀏覽器大戰,其中最著名的兩個角鬥士是網景和微軟。開始的時候微軟壓根不是網景的對手,但微軟最終使用捆綁銷售策略,在 Windows 98 中免費附贈 IE 瀏覽器,據此擊敗網景。IE 從此橫著走了十幾年,還產生了一款讓開發者痛恨欲絕的釘子戶——IE6。

HTML:

在萬維網的 B/S 架構中,瀏覽器測負責資源的展示,具體來說是用一種叫 HTML 的標記語言來展示資源。

HTML 的全稱是 Hyper Text Markup Language,即超文本標記語言,由伯納斯·李和同事丹尼爾·康諾利於 1990 年設計。

在 HTML 中,通過各種標籤(tag,如a、img、div)來標記文本的結構、格式或引用。瀏覽器不但可以展示不同媒體類型的資源,還能夠在一篇文檔(或叫頁面)中組織和展示多種媒體類型的資源,這種頁面我們叫超媒體頁面

可以通過head、body、div、p、tr、td 來管理文檔的結構。

可以通過 i、b、h1 來表達文檔的格式。

可以通過 a、img、audio、video 這些超鏈接標籤給文檔引入文本、圖片、音頻、影片資源,這些資源有可能和當前頁面在同一個伺服器上,也可能位於遙遠的另一台伺服器——萬維網的資源倉庫分布在全球各地。

隨著層疊樣式表 CSS 的出現,HTML 語言的重心逐漸轉向表達文檔的結構,而由 CSS 來負責文檔的布局和樣式。

瀏覽器隨著 HTML、CSS、JavaScript 這些前端語言的發展而愈發強大起來,從最初只能展示基本的 HTML 靜態頁面,到可以通過 CSS 控制各種炫酷的樣式和布局,到通過 JavaScript 實現動態交互,到 ajax 實現動態內容和資訊流式交互。

網關:

伯納斯·李在設計萬維網時,世界上已經存在大量的資訊系統,這些系統間的資訊格式迥異,大多數並不符合萬維網協議標準,但萬維網不能拋棄這些既有資訊。

伯納斯·李提出了網關(Gateway)的概念來解決此問題。

網關其實就是一個文檔格式轉換器:將現有的不符合萬維網標準的文檔轉換成標準文檔,然後發給客戶端

333
伯納斯·李的網關模型

如上圖,瀏覽器訪問 Web 伺服器(左側那個 Hypertext Server),該伺服器會去訪問網關伺服器(右側小的那個),網關伺服器將原始文檔轉換成符合萬維網格式的文檔後返回給 Web 伺服器,Web 伺服器再返回給瀏覽器。這裡只是增加一層網關伺服器,無需修改原始文檔,也不用大面積改造 Web 伺服器。

伯納斯·李這個網關概念和我們今天說的網關伺服器是類似的。我們今天所說的網關主要起到協議轉換作用,它的一頭通過 HTTP 協議和瀏覽器(或者代理)通訊,另一頭通過其他協議(FTP、STMP、fast-cgi 等)和其他應用程式通訊。另外,今天的 Web 伺服器大部分同時也是網關伺服器,如 nginx:

image-20220413225834703
今天的 Web 伺服器網關

如圖,如今網上很大部分內容都是由應用程式動態生成的,當瀏覽器訪問 Web 伺服器時,Web 伺服器並不是在它本地直接找到資源並返回,而是通過諸如 fast-cgi 協議訪問後面的應用程式服務,應用程式生成相關結果返回給 Web 伺服器,Web 伺服器再返回給瀏覽器。對於瀏覽器來說,該過程是透明的,所以對於瀏覽器來說,它就是 Web 伺服器;對於應用程式來說,它將自己返回的 fast-cgi 格式數據轉換成了 HTTP 協議格式數據,因而它是個網關——因而這種網關又叫做伺服器端網關。

有了網關這層轉換,就可以基於現有的數據、現有的服務(如郵件服務)對外提供統一的 HTTP 服務,從而高效快速地接入萬維網。

原文出處:《萬維網:蒂姆·伯納斯·李的資訊帝國》

Tags: