HTTP協議的那些事——1)HTTP概述

原文鏈接 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Overview

HTTP是一種能夠獲取如 HTML 這樣的網絡資源的 protocol(通訊協議)。它是在 Web 上進行數據交換的基礎,是一種 client-server 協議,也就是說,請求通常是由像瀏覽器這樣的接受方發起的。一個完整的Web文檔通常是由不同的子文檔拼接而成的,像是文本、佈局描述、圖片、視頻、腳本等等。

A Web document is the composition of different resources

客戶端和服務端通過交換各自的消息(與數據流正好相反)進行交互。由像瀏覽器這樣的客戶端發出的消息叫做 requests,被服務端迴應的消息叫做 responses。

HTTP as an application layer protocol, on top of TCP (transport layer) and IP (network layer) and below the presentation layer.HTTP被設計於上20世紀90年代初期,是一種可擴展的協議。它是應用層的協議,通過TCP,或者是TLS-加密的TCP連接來發送,理論上任何可靠的傳輸協議都可以使用。因爲其良好的擴展性,時至今日,它不僅被用來傳輸超文本文檔,還用來傳輸圖片、視頻或者向服務器發送如HTML表單這樣的信息。HTTP還可以根據網頁需求,僅獲取部分Web文檔內容更新網頁。

基於HTTP的組件系統

HTTP是一個client-server協議:請求通過一個實體被髮出,實體也就是用戶代理。大多數情況下,這個用戶代理都是指瀏覽器,當然它也可能是任何東西,比如一個爬取網頁生成維護搜索引擎索引的機器爬蟲。

每一個發送到服務器的請求,都會被服務器處理並返回一個消息,也就是response。在這個請求與迴應之間,還有許許多多的被稱爲proxies的實體,他們的作用與表現各不相同,比如有些是網關,還有些是caches等。

實際上,在一個瀏覽器和處理請求的服務器之間,還有路由器、調制解調器等許多計算機。由於Web的層次設計,那些在網絡層和傳輸層的細節都被隱藏起來了。HTTP位於最上層的應用層。雖然底層對於分析網絡問題非常重要,但是大多都跟對HTTP的描述不相干。

客戶端:user-agent

user-agent 就是任何能夠爲用戶發起行爲的工具。這個角色通常都是由瀏覽器來扮演。一些例外情況,比如是工程師使用的程序,以及Web開發人員調試應用程序。

瀏覽器總是作爲發起一個請求的實體,他永遠不是服務器(雖然近幾年已經出現一些機制能夠模擬由服務器發起的請求消息了)。

要展現一個網頁,瀏覽器首先發送一個請求來獲取頁面的HTML文檔,再解析文檔中的資源信息發送其他請求,獲取可執行腳本或CSS樣式來進行頁面佈局渲染,以及一些其它頁面資源(如圖片和視頻等)。然後,瀏覽器將這些資源整合到一起,展現出一個完整的文檔,也就是網頁。瀏覽器執行的腳本可以在之後的階段獲取更多資源,並相應地更新網頁。

一個網頁就是一個超文本文檔。也就是說,有一部分顯示的文本可能是鏈接,啓動它(通常是鼠標的點擊)就可以獲取一個新的網頁,使得用戶可以控制客戶端進行網上衝浪。瀏覽器來負責發送HTTP請求,並進一步解析HTTP返回的消息,以向用戶提供明確的響應。

Web服務端

在上述通信過程的另一端,是由Web Server來服務並提供客戶端所請求的文檔。Server只是虛擬意義上代表一個機器:它可以是共享負載(負載均衡)的一組服務器組成的計算機集羣,也可以是一種複雜的軟件,通過向其他計算機(如緩存,數據庫服務器,電子商務服務器 ...)發起請求來獲取部分或全部資源。

Server 不一定是一臺機器,但一個機器上可以裝載的衆多Servers。在HTTP/1.1 和Host頭部中,它們甚至可以共享同一個IP地址。

代理(Proxies)

在瀏覽器和服務器之間,有許多計算機和其他設備轉發了HTTP消息。由於Web棧層次結構的原因,它們大多都出現在傳輸層、網絡層和物理層上,對於HTTP應用層而言就是透明的,雖然它們可能會對應用層性能有重要影響。還有一部分是表現在應用層上的,被稱爲代理(Proxies)。代理(Proxies)既可以表現得透明,又可以不透明(“改變請求”不會通過它們)。代理主要有如下幾種作用:

  • 緩存(可以是公開的也可以是私有的,像瀏覽器的緩存)
  • 過濾(像反病毒掃描,家長控制...)
  • 負載均衡(讓多個服務器服務不同的請求)
  • 認證(對不同資源進行權限管理)
  • 日誌記錄(允許存儲歷史信息)

HTTP 的基本性質

HTTP 是簡單的

雖然下一代HTTP/2協議將HTTP消息封裝到了幀(frames)中,HTTP大體上還是被設計得簡單易讀。HTTP報文能夠被人讀懂,還允許簡單測試,降低了門檻,對新人很友好。

HTTP 是可擴展的

在 HTTP/1.0 中出現的 HTTP headers 讓協議擴展變得非常容易。只要服務端和客戶端就新 headers 達成語義一致,新功能就可以被輕鬆加入進來。

HTTP 是無狀態,有會話的

HTTP是無狀態的:在同一個連接中,兩個執行成功的請求之間是沒有關係的。這就帶來了一個問題,用戶沒有辦法在同一個網站中進行連續的交互,比如在一個電商網站裏,用戶把某個商品加入到購物車,切換一個頁面後再次添加了商品,這兩次添加商品的請求之間沒有關聯,瀏覽器無法知道用戶最終選擇了哪些商品。而使用HTTP的頭部擴展,HTTP Cookies就可以解決這個問題。把Cookies添加到頭部中,創建一個會話讓每次請求都能共享相同的上下文信息,達成相同的狀態。

注意,HTTP本質是無狀態的,使用Cookies可以創建有狀態的會話。

HTTP 和連接

一個連接是由傳輸層來控制的,這從根本上不屬於HTTP的範圍。HTTP並不需要其底層的傳輸層協議是面向連接的,只需要它是可靠的,或不丟失消息的(至少返回錯誤)。在互聯網中,有兩個最常用的傳輸層協議:TCP是可靠的,而UDP不是。因此,HTTP依賴於面向連接的TCP進行消息傳遞,但連接並不是必須的。

HTTP/1.0爲每一個請求/響應都打開一個TCP連接,導致了2個缺點:打開一個TCP連接需要多次往返消息傳遞,因此速度慢。但當多個消息週期性發送時,這樣就變得更加高效:暖連接比冷連接更高效。

爲了減輕這些缺陷,HTTP/1.1引入了流水線(被證明難以實現)和持久連接的概念:底層的TCP連接可以通過Connection頭部來被部分控制。HTTP/2則發展得更遠,通過在一個連接複用消息的方式來讓這個連接始終保持爲暖連接。 

爲了更好的適合HTTP,設計一種更好傳輸協議的進程一直在進行。Google就研發了一種以UDP爲基礎,能提供更可靠更高效的傳輸協議QUIC

HTTP 能控制什麼

多年以來,HTTP良好的擴展性使得越來越多的Web功能歸其控制。緩存和認證很早就可以由HTTP來控制了。另一方面,對同源同域的限制到2010年纔有所改變。

以下是可以被HTTP控制的常見特性。

  • 緩存 
    文檔如何緩存能通過HTTP來控制。服務端能告訴代理和客戶端哪些文檔需要被緩存,緩存多久,而客戶端也能夠命令中間的緩存代理來忽略存儲的文檔。
  • 開放同源限制
    爲了防止網絡窺聽和其它隱私泄漏,瀏覽器強制對Web網站做了分割限制。只有來自於相同來源的網頁才能夠獲取網站的全部信息。這樣的限制有時反而成了負擔,HTTP可以通過修改頭部來開放這樣的限制,因此Web文檔可以是由不同域下的信息拼接成的(某些情況下,這樣做還有安全因素考慮)。
  • 認證
    一些頁面能夠被保護起來,僅讓特定的用戶進行訪問。基本的認證功能可以直接通過HTTP提供,使用Authenticate相似的頭部即可,或用HTTP Cookies來設置指定的會話。
  • 代理和隧道
    通常情況下,服務器和/或客戶端是處於內網的,對外網隱藏真實 IP 地址。因此 HTTP 請求就要通過代理越過這個網絡屏障。但並非所有的代理都是 HTTP 代理。例如,SOCKS協議的代理就運作在更底層,一些像 FTP 這樣的協議也能夠被它們處理。
  • 會話 
    使用HTTP Cookies允許你用一個服務端的狀態發起請求,這就創建了會話。雖然基本的HTTP是無狀態協議。這很有用,不僅是因爲這能應用到像購物車這樣的電商業務上,更是因爲這使得任何網站都能輕鬆爲用戶定製展示內容了。

HTTP 流

當客戶端想要和服務端進行信息交互時(服務端是指最終服務器,或者是一箇中間代理),過程表現爲下面幾步:

  1. 打開一個TCP連接:TCP連接被用來發送一條或多條請求,以及接受迴應消息。客戶端可能打開一條新的連接,或重用一個已經存在的連接,或者也可能開幾個新的TCP連接連向服務端。
  2. 發送一個HTTP報文:HTTP報文(在HTTP/2之前)是語義可讀的。在HTTP/2中,這些簡單的消息被封裝在了幀中,這使得報文不能被直接讀取,但是原理仍是相同的。
  3. GET / HTTP/1.1
    Host: developer.mozilla.org
    Accept-Language: fr

     
  4. 讀取服務端返回的報文信息:
    HTTP/1.1 200 OK
    Date: Sat, 09 Oct 2010 14:28:02 GMT
    Server: Apache
    Last-Modified: Tue, 01 Dec 2009 20:18:22 GMT
    ETag: "51142bc1-7449-479b075b2891b"
    Accept-Ranges: bytes
    Content-Length: 29769
    Content-Type: text/html
    
    <!DOCTYPE html... (here comes the 29769 bytes of the requested web page)
  5. 關閉連接或者爲後續請求重用連接。

當HTTP流水線啓動時,後續請求都可以不用等待第一個請求的成功迴應就被髮送。然而HTTP流水線已被證明很難在現有的網絡中實現,因爲現有網絡中有很多老舊的軟件與現代版本的軟件共存。因此,HTTP流水線已被在有多請求下表現得更穩健的HTTP/2的幀所取代。

HTTP 報文

HTTP/1.1以及更早的HTTP協議報文都是語義可讀的。在HTTP/2中,這些報文被嵌入到了一個新的二進制結構,幀。幀允許實現很多優化,比如報文頭部的壓縮和複用。即使只有原始HTTP報文的一部分以HTTP/2發送出來,每條報文的語義依舊不變,客戶端會重組原始HTTP/1.1請求。因此用HTTP/1.1格式來理解HTTP/2報文仍舊有效。

有兩種HTTP報文的類型,請求與迴應,每種都有其特定的格式。

請求

HTTP請求的一個例子:

A basic HTTP request

請求由以下元素組成:

  • 一個HTTP的method,經常是由一個動詞像GETPOST 或者一個名詞像OPTIONSHEAD來定義客戶端的動作行爲。通常客戶端的操作都是獲取資源(GET方法)或者發送HTML form表單值(POST方法),雖然在一些情況下也會有其他操作。
  • 要獲取的資源的路徑,通常是上下文中就很明顯的元素資源的URL,它沒有protocolhttp://),domaindeveloper.mozilla.org),或是TCP的port(HTTP一般在80端口)。
  • HTTP協議版本號。
  • 爲服務端表達其他信息的可選頭部headers
  • 對於一些像POST這樣的方法,報文的body就包含了發送的資源,這與迴應報文的body類似。

迴應

HTTP迴應的一個例子:

迴應報文包含了下面的元素:

  • HTTP協議版本號。
  • 一個狀態碼(status code),來告知對應請求執行成功或失敗,以及失敗的原因。
  • 一個狀態信息,這個信息是非權威的狀態碼描述信息,可以由服務端自行設定。
  • HTTP headers,與請求頭部類似。
  • 可選項,比起請求報文,響應報文中更常見地包含獲取的資源body。

總結

HTTP是一種簡單可擴展的協議,其Client-Server的結構以及輕鬆擴展頭部信息的能力使得HTTP可以和Web共同發展。

即使HTTP/2爲了提高性能將HTTP報文嵌入到幀中這一舉措增加了複雜度,但是從Web應用的角度看,報文的基本結構沒有變化,從HTTP/1.0發佈起就是這樣的結構。會話流依舊簡單,通過一個簡單的 HTTP message monitor就可以查看和糾錯。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章