一、TCP/IP
1.TCP/IP協議族
計算機與網路裝置進行通訊,雙方就必須基於相同的方法。比如,如何找到通訊目標,採用哪種語言通訊,如何結束通訊等。這些都需要規則約束,我們把這種規則稱之為協議。
有人認為TCP/IP是指TCP和IP協議。其實,這是片面的。在特定場景下TCP/IP的確指這兩種協議。更多情況下,它指基於IP進行通訊的協議族。因此通常又稱TCP/IP協議族。我們今天要介紹的HTTP就是屬於它的一個子集。
2.TCP/IP分層
TCP/IP採用四層分層模型,自上而下分別為應用層、傳輸層、網路層、資料鏈路層。
模型 | 功能 | 協議族 |
---|---|---|
應用層 | 為使用者提供應用服務通訊。例如:HTTP用於瀏覽;FTP用於檔案傳輸;POP3用於接收郵件;SMTP用於傳送郵件。 | HTTP FTP POP3 SMTP SSH等 |
傳輸層 | 傳輸層為應用層提供資料傳輸服務。 | TCP UDP |
網路層 | 處理在網路上流動的資料包,為資料包選擇路由。 | IP等 |
資料鏈路層 | 在硬體媒體上傳輸資料。 |
3. 資料處理流程
我們以瀏覽器瀏覽網頁為例來說明:
應用層瀏覽器傳送HTTP請求,生成HTTP請求資料。
TCP負責連線、傳送資料、斷開連線。TCP協議保證了HTTP資料包到達接受端的可靠性。為了實現這一功能,需要將HTTP資料分割,併為各個報文新增一個TCP首部。
IP協議,將TCP層傳過來的資料作為自己的資料,並在自己資料前端加上IP首部然後轉發給資料鏈路層。值得一提的是,在IP首部指定了接受端的MAC地址。
接收端在資料鏈路層接收到資料,依次往上層傳遞,直到應用層。至此,接收端接收到了傳送端的HTTP資料。
4.DNS協議
DNS是Domain Name System(域名解析服務)的縮寫,主要負責將域名解析為對應的IP地址。它與HTTP協議一樣位於應用層。
對於使用者來說使用一串有意義的字元去訪問某臺計算機是更容易接受的。例如,用www.baidu.com訪問百度。將使用者容易理解的域名解析為網路傳輸需要的IP,這就是DNS存在的意義。
二、HTTP報文
HTTP之間資料交換的資料資訊被稱之為報文。HTTP報文有兩種:請求報文 和 響應報文。請求報文指從客戶端向服務端傳送的報文。響應報文指從服務端響應客戶端的報文。
這兩種報文都是由 首行、報文首部、報文主體三部分組成的。
請求報文
POST /i HTTP/1.1
Host: count.typora.io
Accept: */*
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Cookie: __cfduid=d345ac732c82bada5e1f1b3ec7f42498e1550563241
Accept-Language: zh-cn
Content-Length: 206
Accept-Encoding: br, gzip, deflate
User-Agent: Typora/1355 CFNetwork/975.0.3 Darwin/18.2.0 (x86_64)
app_key=3162bc659f38963b8f15099e19551
複製程式碼
響應報文
HTTP/1.1 200 OK
Server: nginx
Date: Mon, 11 Mar 2019 03:28:05 GMT
Content-Type: application/json; charset=utf-8
Vary: Accept-Encoding
Access-Control-Allow-Origin: *
X-Frame-Options: deny
X-XSS-Protection: 1; mode=block
Content-Encoding: gzip
Transfer-Encoding: chunked
Connection: Keep-alive
{"result":"Success"}
複製程式碼
1.首行
1.1 請求報文首行
POST /i HTTP/1.1 是請求報文的首行。其中 POST 代表請求方法。 /i 表示請求的資源URI。HTTP/1.1 表示HTTP版本號。
請求方法:告知伺服器請求意圖,期望伺服器產生某種行為。
目前常見的方法有:
方法 | 說明 | HTTP協議版本 |
---|---|---|
GET | 請求已被URI識別的資源 | 1.0、1.1 |
POST | 傳輸實體的主體 | 1.0、1.1 |
PUT | 傳輸檔案 | 1.0、1.1 |
HEAD | HEAD和GET方法一樣,只是不返回響應報文的主體部分 | 1.0、1.1 |
DELETE | 刪除資源 | 1.0、1.1 |
OPTIONS | 詢問支援的方法 | 1.1 |
除了上述幾種方法外,還有TRACE、CONNECT、LINK、UNLINK等。
通常我們只會用到GET、POST方法。GET用來請求訪問已被URI識別的資源,指定的資源經伺服器解析後返回響應結果。POST用來傳輸實體的主體。雖然GET也可以用來傳輸實體的主體,但是一般我們不用,而是用POST。
PUT用來傳輸檔案,但是由於HTTP/1.1的PUT方法不帶驗證機制,存在安全隱患,因此很少用到。
DETETE和PUT存在一樣的問題,因此也很少用到。但是如果伺服器採用了REST風格的設計,PUT和DELETE將會被應用到。
HEAD和GET方法一樣,只是不返回響應報文的主體部分。用來確認URI的有效性和資源更新的日期時間等。例如,客戶端需要一個很大的檔案(幾百兆),如果每次都從網路上載入檔案會造成很大的開銷。為了解決這個問題,客戶端可以在首次GET檔案後進行快取,以後只需要HEAD請求驗證檔案是否更新,只有當檔案更新後才需要重新GET。
URI:資源URI
HTTP版本:目前有 HTTP/1.0、HTTP/1.1、HTTP/2.0。HTTP/1.1版本使用最為廣泛。
1.2 響應報文首行
HTTP/1.1 200 OK 是響應報文的首行。其中HTTP/1.1已經介紹過了,與請求報文首行中的HTTP版本號相同。200表示返回結果的狀態碼。OK表示原因短語。
狀態碼
狀態碼的職責是當客戶端向服務端傳送請求時,描述返回的請求結果。
狀態碼 | 說明 |
---|---|
1xx | 表示接受的請求正在處理 |
2xx | 表示成功 |
3xx | 表示重定向 |
4xx | 表示客戶端錯誤 |
5xx | 表示伺服器錯誤 |
2.報文首部
Host: count.typora.io
Accept: */*
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Cookie: __cfduid=d345ac732c82bada5e1f1b3ec7f42498e1550563241
Accept-Language: zh-cn
Content-Length: 206
Accept-Encoding: br, gzip, deflate
User-Agent: Typora/1355 CFNetwork/975.0.3 Darwin/18.2.0 (x86_64)
複製程式碼
報文的首部欄位表示請求的各種條件和屬性,它能起到傳遞額外重要資訊的作用。根據其用途的不同可以分為以下四種:通用首部欄位、請求首部欄位、響應首部欄位、實體首部欄位。
-
通用首部欄位
請求報文和響應報文都會用到的首部。
-
請求首部欄位
請求報文用到的首部。
-
響應首部欄位
響應報文用到的首部。
-
實體首部欄位
針對請求報文和響應報文的實體部分使用的首部。
HTTP/1.1定義了47種首部欄位。我們當然不會全部介紹,因為比較常用的也就那麼幾種。現在,我會列出一個表格,將HTTP的特性和這些常用的首部欄位對應上。當然,隨後我們會詳細的介紹這些特性和首部欄位,但是現在,這僅僅是一個列表。
HTTP特性 | 首部 | 首部型別 | 描述 |
---|---|---|---|
無狀態 | Set-Cookie | 響應首部 | 伺服器下發給客戶端的Cookie資訊,表示伺服器已經記下的客戶端的身份資訊 |
Cookie | 請求首部 | 客戶端請求伺服器時攜帶的Cookie資訊,表明自己的身份資訊 | |
持久連線 | Connection | 通用首部 | 管理連線狀態 |
快取 | Cache-Control | 通用首部 | 操作快取的工作機制 |
Last-Modified | 實體首部 | 資源最終修改時間(伺服器時間) | |
If-Modified-Since | 請求首部 | 其值是一個時間。告知伺服器若If-Modified-Since欄位值早於資源更新時間,處理該請求 | |
ETag | 響應首部 | 當前資源的唯一標識。資源改變,ETag也會改變 | |
If-None-Match | 請求首部 | 與ETag結合使用,告知伺服器若If-None-Match值(ETag)和資源ETag不一致,處理該請求 |
3.實體
這個好像沒什麼好說的 過掉它吧!!!
三、HTTP特性
1.無狀態
無狀態 | Set-Cookie | 響應首部 | 伺服器下發給客戶端的Cookie資訊,表示伺服器已經記下的客戶端的身份資訊 |
---|---|---|---|
Cookie | 請求首部 | 客戶端請求伺服器時攜帶的Cookie資訊,表明自己的身份資訊 |
HTTP 是一種無狀態協議,即HTTP不會管理之前客戶端與伺服器的通訊狀態。由於不用儲存通訊狀態,那麼伺服器的CPU以及記憶體的壓力會大大降價。這是HTTP無狀態的優點,但它也會給我們帶來一些的問題。例如,我們去某購物網站購物,提交訂單之前要對我們的身份進行驗證(需要我們登入賬號)。但是由於HTTP的無狀態特性(沒有記錄登入狀態),每次下單都會要求我們重新登入。為了即不破壞HTTP的無狀態特性又可以解決類似的問題,HTTP引入了Cookie技術。Cookie技術通過在請求報文和響應報文中加入cookie資訊來實現狀態的保持。在響應報文中,伺服器可以通過set-cookie首部告訴客戶端Cookie資訊。客戶端再次請求時會通過Cookie首部攜帶上Cookie資訊。
2.持久連線
持久連線 | Connection | 通用首部 | 管理連線狀態 |
---|
前面我們在TCP/IP中介紹過,HTTP依賴於TCP進行資料傳輸。如果你瞭解過TCP,你應該知道TCP是一種穩定的長連線,即如果沒有一方明確的提出過斷開連線,那麼連線將一直持續。在早些年的HTTP協議中,每進行一次HTTP通訊,都會有一次TCP的連線與斷開。這與TCP的長連線特性相違背。因此,在HTTP/1.1和部分HTTP/1.0中增加了持久連線(HTTP persistent connection,也稱作HTTP keep-alive或HTTP connection reuse),使用同一個TCP連線來傳送和接受多個HTTP通訊,而不是為每一次通訊都開啟新的連線。HTTP就是通過Connection首部來管理持久連線的。
Connection的值 | 描述 |
---|---|
Connection:keep-alive | HTTP/1.1預設是keep-alive,表示該連線是持久連線 |
Connection:close | 斷開連線 |
3.快取機制
快取 | Cache-Control | 通用首部 | 操作快取的工作機制 |
---|---|---|---|
Last-Modified | 實體首部 | 資源最終修改時間(伺服器時間) | |
If-Modified-Since | 請求首部 | 其值是一個時間。告知伺服器若If-Modified-Since欄位值早於資源更新時間,處理該請求 | |
ETag | 響應首部 | 當前資源的唯一標識。資源改變,ETag也會改變 | |
If-None-Match | 請求首部 | 與ETag結合使用,告知伺服器若If-None-Match值(ETag)和資源ETag不一致,處理該請求 |
HTTP允許客戶端在一次URL請求完成後將響應結果儲存到本地。下次向該URL請求資源時,客戶端會直接從本地儲存中獲取到該URL的資源。這就是HTTP的快取機制。合理的利用快取機制,既可以為我們節省網路資源,又可以加快請求反饋。
引入了快取機制後,HTTP請求會變的稍微複雜一點。
- 當我們初次訪問一個URL時,伺服器返回請求資源並同時告訴客戶端對資源進行快取、以及快取過期時間。
- 再次訪問該URL時,客戶端會根據URI找到對應的快取,並檢查快取是否有效(當前時間小於快取的過期時間)。
- 若快取有效,客戶端不會去訪問伺服器,而是直接從快取中獲取資源,這個過程我們稱為快取命中。
- 若快取無效(當前時間大於快取的過期時間),客戶端會去向伺服器驗證快取是否有效。
- 有效,伺服器僅返回代表快取有效的首部資訊,客戶端更新快取過期時間,同時從快取中取得資源。
- 無效,伺服器返回新的資源,客戶端更新資源。
對HTTP的快取流程有了一定的瞭解之後,我們就可以繼續探討快取的具體實現了。
第一步中,我們知道伺服器會告訴客戶端快取的過期時間,那麼這個時間是怎麼確定的呢?這是由伺服器在響應報文中加入Cache-Control:max-age來實現的。max-age後面會跟一個相對時間,意思是快取的有效時間。例如,Cache-Control:max-age=60表示快取在60秒內有效。需要注意的是,Cache-Control是HTTP/1.1才定義的欄位,在HTTP/1.0的版本中過期時間是通過Expire欄位實現的。Exprie有一個缺陷,它返回的到期時間是伺服器的絕對時間,這就導致如果客戶端時間和伺服器時間不一致,那麼快取的時間不正確。如果我們的頭部同時設定了Cache-Control:max-age和Expire,在HTTP/1.1中會優先使用Cache-Control:max-age,而在HTTP/1.0中會直接忽略掉Cache-Control首部。
第二、三步比較簡單,沒什麼要額外說明的。
第四步中,我們知道當快取失效,客戶端會再次向伺服器驗證。那麼客戶端是如何向伺服器驗證的呢?其實,第一步中,伺服器除了返回Cache-Control首部資訊外,還會返回一個Last-Modified欄位,它的值是資源的最近更改時間(伺服器時間)。當客戶端向伺服器驗證快取的有效性時,會在請求首部加上If-Modified-Since,它的值就是Last-Modified的值。伺服器根據If-Modified-Since攜帶的時間就能判斷出客戶端快取資源與伺服器資源是否一致。如果一致伺服器會返回狀態碼304(Not Modified),此時是不會返回任何實體資訊的。如果不一致,伺服器返回狀態碼200(success),同時也會返回資源資訊。無論是返回304還是200,客戶端都會重新更新快取(304只更新過期時間,200更新過期時間和資源)。
除了Last-Modified/If-Modified-Since外,還可以用ETag/If-None-Match管理快取。ETag為每一個資源打上一個唯一標識,資源變化都會導致ETag變化。If-None-Match驗證的就是資源的ETag有沒有發生變化。其餘的邏輯和Last-Modified/If-Modified-Since基本相同,我就不贅述了。
快取機制極大的提高了HTTP訪問效率,但又引入了實時性問題。因此HTTP提供更嚴格的快取控制方式:Cache-Control:no-cache
和Cache-Control:no-store
。
Cache-Control:no-cache
表示客戶端不能直接使用本地快取,必須向伺服器驗證快取的有效性。而不是字面意思上的不快取。
Cache-Control:no-store
表示客戶端不能對資源進行快取。
上面說了那麼多,其實就是為了引出這張圖。
四、HTTPS
在介紹HTTPS之前,我們先了解一下HTTP有哪些缺點:
- 通訊採用明文,內容可能會被竊聽。
- 不驗證通訊方身份,有可能遭遇偽裝。
- 無法驗證報文的完整性,有可能報文已遭篡改。
為了解決以上問題,HTTPS應運而生了。HTTPS並非是一種應用層的新協議。而是在HTTP和TCP之間加入了SSL\TLS。一般,HTTP直接和TCP通訊。而採用HTTPS後,HTTP先和SSL\TLS通訊,再由SSL\TLS和TCP通訊。SSL提供了認證、加密等功能。《圖解HTTP》一書中對HTTPS的描述是HTTPS=HTTP+加密+認證+完整性保護。
1.加密
常用的加密方式有兩種:對稱加密、非對稱加密。
對稱加密是指使用同一把祕鑰加密和解密的演算法。這種演算法的優點是加密速度快,缺點是必須把祕鑰傳送給對方。可祕鑰傳輸的過程中,我們怎樣才能確保它不會被攔截呢?
非對稱加密是指需要一對(兩個)祕鑰加密和解密的演算法。這一對祕鑰一個是公鑰,另一個是私鑰。顧名思義,公鑰可以隨意對外公開,私鑰只能自己持有。用公鑰加密的密文只有用對應的私鑰才能解密,而用私鑰加密的密文也只有對應的公鑰才能解密。這種加密演算法的缺點就是速度慢。
SSL/TLS採用兩者結合的混合加密方式。伺服器首先採用非對稱加密的方式將一個對稱祕鑰加密後傳輸給客戶端,客戶端使用公鑰解密出對稱祕鑰。隨後雙方採用對稱加密通訊。這樣就可以兼顧對稱加密和非對稱加密各自的優點。
2.證書
上述的SSL/TLS加密還存在一個問題,那就是無法驗證公鑰的正確性。比如,伺服器在向客戶端傳輸公鑰的過程中,公鑰已經被篡改了。為了解決這個問題,可以使用數字認證機構和其頒發的公鑰認證證書。數字認證機構是一個客戶端和伺服器都信任的第三方機構,其頒發的公鑰認證證書在目前看來是很難被篡改的。我們簡單介紹一下證書的工作流程。首先,伺服器的運營人員向數字證書認證機構提出公祕證書申請。請求通過後,數字證書認證機構會對公鑰做數字簽名,並將公鑰和數字證書繫結。伺服器會將這個證書傳送給客戶端,接到證書的客戶端可以使用數字證書認證機構的公鑰對數字簽名進行驗證。驗證通過,則表明該證書可信。
這裡需要額外說明的兩點,一、客戶端(瀏覽器或作業系統)會內建常用的可信數字證書認證機構的公開祕鑰。二、數字證書除了包含公鑰外還包含了伺服器的身份資訊,因此我們也可以用證書來確認對方身份。
3.對稱祕鑰的生成過程
這個過程,其實非常複雜。我將其簡化如下圖。