目錄
HTTP概述
非持續連接和持續連接
非持續連接
持續連接
HTTP報文格式
HTTP請求報文
HTTP響應報文?
Web緩存
條件GET方法
Web 即萬維網,是一個基于超文本和 HTTP 協議的全球性信息系統,通過瀏覽器訪問,以網頁形式呈現信息。HTTP 是客戶端和服務器之間進行數據傳輸的協議,用于 Web 上的信息交互。
和傳統的廣播或者電視不同,它們使用戶只能被迫收聽或者觀看內容傳播者所投放的節目。而Web可以按需所操作獲取想要的內容。并且在Web上發布內容也很簡單,只需很低的代價就能成為內容傳播者,超鏈接和搜索引擎也能幫我們很好的來訪問內容。
HTTP概述
HTTP是超文本傳輸協議,是Web應用核心的傳輸協議,在RFC中有所定義。它由兩個程序實現:一個客戶程序和一個服務器程序。客戶程序和服務器程序運行在兩個不同的端系統中,通過交換HTTP報文進行交互(也可以在同一個端系統中)。HTTP協議則定義了這個報文的結構以及交換的方式。
Web是由一個個對象構成的,一個對象只是一個文件,例如一個基本的HTML文件,一個網絡圖片,一段CSS樣式表等等,他們可以通過一段URL尋址。多數的Web界面都會有一個HTML基本文件以及幾個引用的對象。例如在一個Web頁面中,包含了一段HTML文件,一段CSS樣式表和一個網絡JPEG圖片,那么這個Web頁面就由三個對象構成,HTML 文件通過特定標簽的屬性中所包含的 URL 來引用其他對象,例如:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><!-- 鏈接外部CSS樣式表 --><link rel="stylesheet" href="styles.css"><title>示例網頁</title>
</head>
<body><header><h1>歡迎來到我的網站</h1></header><main><p>這是一個包含CSS樣式和網絡圖片的示例頁面。</p><!-- 展示網絡圖片 --><img src="https://www.example.com/blog/article.php" alt="示例圖片"></main><footer><p>? 2025 示例網站版權所有</p></footer>
</body>
</html>
URL(統一資源定位符號)一般格式如下:
scheme://host[:port]/path[?query][#fragment]
scheme(協議):指定訪問資源所使用的協議,常見的有http
(超文本傳輸協議)、https
(加密的超文本傳輸協議)、ftp
(文件傳輸協議)、mailto
(郵件協議)等。例如,https://
表示使用安全的超文本傳輸協議來訪問資源。
host(主機名):標識資源所在的服務器的域名或 IP 地址。例如,www.example.com
或192.168.1.1
。
port(端口號):可選部分,用于指定服務器上的特定端口,不同的協議有默認的端口號,如http
默認端口是 80,https
默認端口是 443。如果使用默認端口,通常可以省略不寫;如果使用非默認端口,則需要明確指定,例如http://www.example.com:8080
。
path(路徑):指定服務器上資源的具體路徑,用于定位服務器上的特定文件或資源。例如,/index.html
表示服務器根目錄下的index.html
文件,/blog/posts/123.html
表示blog
目錄下posts
子目錄中的123.html
文件。
query(查詢參數):可選部分,用于向服務器傳遞額外的參數信息,多個參數之間用&
符號分隔。例如,?name=John&age=30
表示傳遞了兩個參數name
和age
,其值分別為John
和30
。
fragment(片段標識符):可選部分,用于指定頁面內的特定位置或錨點。例如,#section1
表示頁面中的id
為section1
的元素位置,瀏覽器會自動滾動到該位置。
以https://www.example.com/blog/article.php?id=123#comments
為例,https
是協議,www.example.com
是主機名,/blog/article.php
是路徑,?id=123
是查詢參數,#comments
是片段標識符。
Web瀏覽器實現了HTTP的客戶端,Web服務器實現了HTTP的服務器端,它用于存儲Web對象,每個對象由URL尋址。
HTTP定義了客戶向服務器請求Web頁面的方式,以及服務器向客戶傳輸Web頁面的方式。HTTP使用TCP作為他的支撐傳輸協議。HTTP客戶首先發起一個與服務器的TCP連接,一旦連接建立,該瀏覽器和服務器進程就可以通過套接字訪問TCP。一旦客戶向他的套接字發送了一個請求報文,該報文就脫離了用戶控制并進入了TCP控制。TCP為HTTP提供了可靠的數據傳輸服務。客戶發出的每一個HTTP請求都會完整的發送到服務器;類似的,服務器最終響應的HTTP報文也能完整的傳輸給客戶。
但是HTTP協議是一個無狀態協議,比如某個客戶向同一個HTTP在短時間內發起同一個HTTP請求,服務器不會因為剛剛已經給了那個用戶響應而不再提供響應,而是會重新發送該對象。同時我們也注意到Web使用了CS體系架構,Web服務器總是開著的,而且他的服務可能來自于數以萬計的不同瀏覽器請求。就比如當你已經加載好了一個網站界面,再次點擊加載(通常是點擊瀏覽器的刷新按鈕)時,瀏覽器會向服務器重新發送請求,服務器會根據請求重新處理并返回相應的內容,從而實現界面的刷新。
非持續連接和持續連接
非持續連接
每個請求 / 響應是經過一個單獨的 TCP 連接發送。即每一次請求一個對象(如一個網頁、一張圖片等)都要建立一個新的 TCP 連接,當服務器發送完一個對象后,該 TCP 連接就會被關閉。例如,一個網頁中有 10 張圖片,使用非持續連接時,就需要建立 10 + 1 個 TCP 連接(1 個連接用于獲取網頁的 HTML 文件,10 個連接分別用于獲取 10 張圖片)。
每一次的連接都涉及到TCP的三次握手過程:即客戶向服務器發送一個小的tcp報文,服務器用一段小的tcp報文段做出確認和響應,最后客戶向服務器返回確認。前面兩個過程就消耗了一個RTT的時間,在算上后面確認響應到達服務器,服務器傳輸響應的文件這一段也消耗了一次RTT。所以粗略的講,總的響應時間就是兩個RTT加上服務器傳輸文件的時間。
所以這有一個很明顯的缺點,就是必須為每一個請求的對象建立和維護一個全新的連接,對于每一個連接,在客戶和服務器中都要為此分配TCP的緩沖區以及維護TCP變量,相對于客戶端來說,服務器的壓力就會很大,因為一臺服務器可能會受到成千上萬的處理響應。同時每一個連接都要經過兩個RTC的交付時延。
持續連接
所有的請求 / 響應經相同的 TCP 連接發送。服務器在發送響應后保持該 TCP 連接打開,在相同的客戶端和服務器之間,后續的請求和響應報文能夠通過相同的連接進行傳送。例如,對于一個包含多個圖片的網頁,使用持續連接時,只需建立一次 TCP 連接,就可以通過這個連接獲取網頁的 HTML 文件以及所有的圖片。
持續連接減少了 TCP 連接的建立次數,從而減少了連接建立的延遲,提高了效率。在流水線方式下,客戶在收到 HTTP 的響應報文之前就能夠接著發送新的請求報文。服務器會按順序依次響應。在理想情況下,使用流水線方式時,多個請求可以在一個 RTT 內發出,服務器也能在一個 RTT 內開始依次返回響應,因此每個請求的 RTT 理論上可以遠小于一個 RTT,從而大大提高了效率,減少了整體的響應時間。
但是服務器需要維持連接狀態,以處理后續的請求,這需要一定的資源開銷。如果連接長時間不被使用,會占用服務器資源,因此服務器通常會設置一個超時時間,當連接在一定時間內沒有活動時,就會關閉連接。HTTP默認使用的時流水線方式的持續連接。
HTTP報文格式
HTTP報文通常由:請求行/狀態行+首部行+空行+實體體構成。
HTTP請求報文
下面提供了一個經典的HTTP請求報文:
GET /products HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: text/html,application/xhtml+xml
Accept-Language: en-US,en;q=0.5
Connection: keep-alive[消息體為空]
請求行由:方法+sp+URL+sp+版本+cr/lf 構成.
方法字段可以取不同的值,包括GET、POST、HEAD、PUT和DELETE。
GET:向服務器請求獲取指定資源。比如訪問網頁時,瀏覽器用 GET 方法請求服務器返回網頁內容;調用數據接口獲取信息,也是通過 GET 方法。服務器會將請求資源內容放在響應報文數據部分回傳。
POST:向服務器提交數據進行處理。如用戶注冊登錄時提交表單信息,文件上傳時將文件數據發送給服務器,服務器接收到數據后進行相應處理,如存儲到數據庫。
HEAD:和 GET 類似,請求獲取資源信息,但只返回響應頭部,不返回資源內容主體。可用于獲取資源元數據,如資源最后修改時間、內容長度、類型等信息。
PUT:將請求中的數據上傳到服務器指定資源位置,一般用于更新服務器上已存在資源。若資源不存在,可能會創建新資源。
DELETE:請求服務器刪除指定資源,資源由請求的 URL 標識。
首部行由 首部字段名+sp+值+cr/lf 組成.用于傳遞請求的附加信息.
空行由回車(CR
)和換行(LF
)兩個字符組成,即CR LF
。它的作用是分隔 HTTP 報文的首部行和實體體,讓客戶端和服務器能明確區分報文的不同部分,便于正確解析和處理。
實體體(Entity Body)是 HTTP 請求或響應報文中位于首部行之后的數據部分,它承載了實際要傳輸的內容
HTTP響應報文?
下面提供了一個經典的HTTP響應報文:
HTTP/1.1 200 OK
Date: Fri, 09 May 2025 12:00:00 GMT
Server: Apache/2.4.52 (Ubuntu)
Content-Type: text/html; charset=UTF-8
Content-Length: 1234<!DOCTYPE html>
<html>
<head><title>Welcome to Example.com</title>
</head>
<body><h1>Hello, World!</h1>
</body>
</html>
和請求報文不同的是,響應報文的請求行換成了狀態行。
狀態行由 版本+sp+狀態碼+sp+短語+cr/lf 構成.
通過狀態行,客戶端能夠快速了解服務器對請求的處理情況,進而采取相應的措施,如根據不同的狀態碼來決定是否顯示錯誤信息、是否繼續請求其他資源等。
一些常見的狀態碼和短語如下:
- 200 OK:表示請求成功,服務器已成功處理請求,并將請求的資源返回給客戶端。
- 301 Moved Permanently3:表示請求的資源已永久移動到新位置,并且將來任何對此資源的引用都應該使用本響應返回的若干個 URI 之一。
- 400 Bad Request:客戶端發送的請求有語法錯誤或無法被服務器理解,通常是由于請求參數不正確、缺少必要的首部字段、請求格式錯誤等原因導致。
- 404 Not Found5:客戶端請求的資源在服務器上未找到,可能是因為資源不存在、路徑錯誤、被刪除或尚未創建等原因。
- 505 HTTP Version Not Supported:服務器不支持請求中所使用的 HTTP 協議版本。
用戶與服務器的交互:cookie
前面我們說到,HTTP服務是無狀態服務,而 Cookie 的出現正是為了解決 HTTP 的無狀態性帶來的一些問題,它可以實現狀態的保存,記錄用戶的偏好以及跟蹤用戶的行為。
當用戶訪問網站時,服務器通過響應報文首部行中的Set - Cookie
字段向瀏覽器發送 Cookie,包含名稱、值及其他屬性,如過期時間、域名等。瀏覽器接收后,根據Set - Cookie
中的信息將 Cookie 存儲在本地。
當用戶再次訪問同一網站或相關域名下的頁面時,瀏覽器會在請求報文首部行中的Cookie
字段中自動帶上之前存儲的 Cookie,發送給服務器。服務器收到請求后,從Cookie
字段中讀取相關信息,識別用戶身份、獲取用戶設置或跟蹤用戶行為等,然后根據這些信息生成相應的響應內容返回給瀏覽器。
雖然cookie帶來了很多的遍歷,但是它也帶來一系列的隱私問題。
Web緩存
Web緩存器也叫做代理服務器,它能夠代表初始Web服務器來滿足HTTP請求的網絡實體。Web緩存器有自己的磁盤存儲空間,并在存儲空間中保留最近請求過的對象副本。它相當于起到了一個中介的作用。它可以獲取就近的內容,減少重復的請求。同時也可以緩解骨干網絡的壓力,起到一個分擔作用等等。
比如瀏覽器正在請求一個對象,它會先創建一個到Web緩存器的TCP連接,并且向Web緩存器發起一個HTTP請求。接著緩存器進行檢查,檢查是否有該請求對象的副本,如果有就向該客戶瀏覽器發送HTTP響應報文返回該對象,如果沒有,他就接著和初始Web服務器進行一個TCP連接,初始Web服務器就向Web緩存器發起一個HTTP響應報文返回該對象,接著Web緩存器保留該副本,接著向客戶瀏覽器返回一個響應報文返回該對象。
所以Web緩存器又可以作為客戶端,也可以作為服務端。它通常由ISP(網絡服務提供商)購買并且安裝。
我們來通過一個特別簡單的例子來講述安裝Web緩存器的好處。假設有兩個網絡,一個是公共因特網,一個是高速的機構網絡(局域網)。初始的Web服務器分布在世界各地,與因特網相連,然后機構網絡上的一個路由器通過一個15Mbps的鏈路和因特網上的一個路由器相連接,接入網本地由100Mbps的鏈路相連接。假設初始Web服務器的平均訪問速率是每秒15個請求,假設請求對象的長度為1Mb,那我們可以粗略的估算一下鏈路上的流量強度:
在因特網鏈路上的流量強度:15個請求/秒 * 1Mb一個請求 / 15 Mbps =1
在機構網鏈路上的流量強度:15個請求/秒 * 1Mb一個請求 / 100?Mbps =0.15
我們假設因特網接入鏈路一側的路由器轉發HTTP報文到它響應報文的平均時間為2s,這也叫做“因特網時延”。
0.15的通信量最多導致數十毫秒的時延,因此我們可以忽略不記。但是在因特網上的時延不可以忽略不計,當流量強度為1的時候,鏈路上的時延會變得非常大并且無限延長。一個最直接的方式就是升級物理鏈路,把他提升到100Mbps甚至更高。但是這會造成一筆不小的費用,通常網絡服務提供商不會這么做,用戶也不會買單。
那如果在機構網本地接入一個Web緩存器當中介呢?假設他的緩存Cache為0.4,有40%的請求會立即得到Web緩存器的響應。接下來我們來算一下時延:
由于只有60%的請求會通過因特網的鏈路,所以流量強度也會因此減少,從1.0減到0.6,所以時延也會因此降低,在15Mbps的鏈路上大約為幾十毫秒,但是這和因特網時延相比也是微不足道的。考慮這些后,我們來算一下平均時延:
0.6*2.01 +0.4*0.01 =1.21?
這和原來相比足足快了0.8秒。
條件GET方法
雖然說Web緩存減少了緩存時間,提高了用戶的體驗,但是這也會引發一個問題,就是存在Web緩存器里面的內容是舊的,也就是已經被用戶修改過的。但HTTP有一個條件GET首部行,在請求報文首部行添加: If-modified-since ,讓服務器僅在資源發生變化時返回新內容,否則返回 “304 Not Modified” 狀態碼,告知客戶端使用本地緩存,通過 “按需獲取” 避免冗余數據傳輸,提升 Web 性能。
🍵🍵🍵.