計算機與網絡設備進行通訊,雙方就必須基於相同的方法。好比,如何找到通訊目標,採用哪一種語言通訊,如何結束通訊等。這些都須要規則約束,咱們把這種規則稱之爲協議。前端
有人認爲TCP/IP是指TCP和IP協議。其實,這是片面的。在特定場景下TCP/IP的確指這兩種協議。更多狀況下,它指基於IP進行通訊的協議族。所以一般又稱TCP/IP協議族。咱們今天要介紹的HTTP就是屬於它的一個子集。nginx
TCP/IP採用四層分層模型,自上而下分別爲應用層、傳輸層、網絡層、數據鏈路層。算法
模型 | 功能 | 協議族 |
---|---|---|
應用層 | 爲用戶提供應用服務通訊。例如:HTTP用於瀏覽;FTP用於文件傳輸;POP3用於接收郵件;SMTP用於發送郵件。 | HTTP FTP POP3 SMTP SSH等 |
傳輸層 | 傳輸層爲應用層提供數據傳輸服務。 | TCP UDP |
網絡層 | 處理在網絡上流動的數據包,爲數據包選擇路由。 | IP等 |
數據鏈路層 | 在硬件媒體上傳輸數據。 |
咱們以瀏覽器瀏覽網頁爲例來講明:json
應用層瀏覽器發送HTTP請求,生成HTTP請求數據。瀏覽器
TCP負責鏈接、發送數據、斷開鏈接。TCP協議保證了HTTP數據包到達接受端的可靠性。爲了實現這一功能,須要將HTTP數據分割,併爲各個報文添加一個TCP首部。緩存
IP協議,將TCP層傳過來的數據做爲本身的數據,並在本身數據前端加上IP首部而後轉發給數據鏈路層。值得一提的是,在IP首部指定了接受端的MAC地址。安全
接收端在數據鏈路層接收到數據,依次往上層傳遞,直到應用層。至此,接收端接收到了發送端的HTTP數據。bash
DNS是Domain Name System(域名解析服務)的縮寫,主要負責將域名解析爲對應的IP地址。它與HTTP協議同樣位於應用層。服務器
對於用戶來講使用一串有意義的字符去訪問某臺計算機是更容易接受的。例如,用www.baidu.com訪問百度。將用戶容易理解的域名解析爲網絡傳輸須要的IP,這就是DNS存在的意義。cookie
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"}
複製代碼
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.一、HTTP/2.0。HTTP/1.1版本使用最爲普遍。
HTTP/1.1 200 OK 是響應報文的首行。其中HTTP/1.1已經介紹過了,與請求報文首行中的HTTP版本號相同。200表示返回結果的狀態碼。OK表示緣由短語。
狀態碼
狀態碼的職責是當客戶端向服務端發送請求時,描述返回的請求結果。
狀態碼 | 說明 |
---|---|
1xx | 表示接受的請求正在處理 |
2xx | 表示成功 |
3xx | 表示重定向 |
4xx | 表示客戶端錯誤 |
5xx | 表示服務器錯誤 |
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不一致,處理該請求 |
這個好像沒什麼好說的 過掉它吧!!!
無狀態 | Set-Cookie | 響應首部 | 服務器下發給客戶端的Cookie信息,表示服務器已經記下的客戶端的身份信息 |
---|---|---|---|
Cookie | 請求首部 | 客戶端請求服務器時攜帶的Cookie信息,代表本身的身份信息 |
HTTP 是一種無狀態協議,即HTTP不會管理以前客戶端與服務器的通訊狀態。因爲不用保存通訊狀態,那麼服務器的CPU以及內存的壓力會大大降價。這是HTTP無狀態的優勢,但它也會給咱們帶來一些的問題。例如,咱們去某購物網站購物,提交訂單以前要對咱們的身份進行驗證(須要咱們登陸帳號)。可是因爲HTTP的無狀態特性(沒有記錄登陸狀態),每次下單都會要求咱們從新登陸。爲了即不破壞HTTP的無狀態特性又能夠解決相似的問題,HTTP引入了Cookie技術。Cookie技術經過在請求報文和響應報文中加入cookie信息來實現狀態的保持。在響應報文中,服務器能夠經過set-cookie首部告訴客戶端Cookie信息。客戶端再次請求時會經過Cookie首部攜帶上Cookie信息。
持久鏈接 | 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 | 斷開鏈接 |
緩存 | 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請求會變的稍微複雜一點。
對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首部。
第2、三步比較簡單,沒什麼要額外說明的。
第四步中,咱們知道當緩存失效,客戶端會再次向服務器驗證。那麼客戶端是如何向服務器驗證的呢?其實,第一步中,服務器除了返回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以前,咱們先了解一下HTTP有哪些缺點:
爲了解決以上問題,HTTPS應運而生了。HTTPS並不是是一種應用層的新協議。而是在HTTP和TCP之間加入了SSL\TLS。通常,HTTP直接和TCP通訊。而採用HTTPS後,HTTP先和SSL\TLS通訊,再由SSL\TLS和TCP通訊。SSL提供了認證、加密等功能。《圖解HTTP》一書中對HTTPS的描述是HTTPS=HTTP+加密+認證+完整性保護。
經常使用的加密方式有兩種:對稱加密、非對稱加密。
對稱加密是指使用同一把祕鑰加密和解密的算法。這種算法的優勢是加密速度快,缺點是必須把祕鑰發送給對方。可祕鑰傳輸的過程當中,咱們怎樣才能確保它不會被攔截呢?
非對稱加密是指須要一對(兩個)祕鑰加密和解密的算法。這一對祕鑰一個是公鑰,另外一個是私鑰。顧名思義,公鑰能夠隨意對外公開,私鑰只能本身持有。用公鑰加密的密文只有用對應的私鑰才能解密,而用私鑰加密的密文也只有對應的公鑰才能解密。這種加密算法的缺點就是速度慢。
SSL/TLS採用二者結合的混合加密方式。服務器首先採用非對稱加密的方式將一個對稱祕鑰加密後傳輸給客戶端,客戶端使用公鑰解密出對稱祕鑰。隨後雙方採用對稱加密通訊。這樣就能夠兼顧對稱加密和非對稱加密各自的優勢。
上述的SSL/TLS加密還存在一個問題,那就是沒法驗證公鑰的正確性。好比,服務器在向客戶端傳輸公鑰的過程當中,公鑰已經被篡改了。爲了解決這個問題,可使用數字認證機構和其頒發的公鑰認證證書。數字認證機構是一個客戶端和服務器都信任的第三方機構,其頒發的公鑰認證證書在目前看來是很難被篡改的。咱們簡單介紹一下證書的工做流程。首先,服務器的運營人員向數字證書認證機構提出公祕證書申請。請求經過後,數字證書認證機構會對公鑰作數字簽名,並將公鑰和數字證書綁定。服務器會將這個證書發送給客戶端,接到證書的客戶端可使用數字證書認證機構的公鑰對數字簽名進行驗證。驗證經過,則代表該證書可信。
這裏須要額外說明的兩點,1、客戶端(瀏覽器或操做系統)會內置經常使用的可信數字證書認證機構的公開祕鑰。2、數字證書除了包含公鑰外還包含了服務器的身份信息,所以咱們也能夠用證書來確認對方身份。
這個過程,其實很是複雜。我將其簡化以下圖。