HTTP 協議在日常網絡應用中隨處可見,我們在任何時候網上衝浪都會看到 HTTP 協議或 HTTPS 協議的身影。既然其普遍存在,那麼就要對它們有一個較爲全面的瞭解!本篇從 HTTP 入手,最後對 HTTPS 進行學習記錄。
文章目錄
引
HTTP 協議通常承載於 TCP 協議之上,有時也會承載於 TLS 或 SSL 協議層之上,這時就成了 HTTPS 協議!HTTP 的默認端口號是 80、HTTPS 的默認端口號是 443。
圖片出自——《圖解HTTP》
HTTP 協議是一個無狀態協議,並且採用"客戶端請求、服務器應答"模式,這也就意味着服務器無法主動向客戶端推送消息、更不能向客戶端發起請求!
正文
簡述 HTTP 工作流程
- HTTP 開始工作,首先客戶端與服務器需要在經歷 TCP 三次握手後建立連接。
- 建立連接之後,客戶端發送一個請求(request)給服務器。
- 服務器收到請求後開始處理,給予客戶端一個響應(response)。(不一定是成功)
- 客戶端接收到響應後處理渲染後告訴用戶,最後斷開連接。
四步中的有任何一步出現錯誤,錯誤信息都將返回到客戶端。
短連接和長連接?
短連接:每次請求都建立一個 TCP 連接,請求完成後結束連接,新的請求再建立 TCP 連接,缺點很明顯就是開銷很大。
長連接:發起一個請求之後,建立 TCP 連接,這條客戶端和服務器之間用於傳輸 HTTP 數據的 TCP 連接不會關閉,但是他有一個保持時間,一般可以在服務器軟件中設定這個時間。使用長連接需要客戶端和服務端都支持長連接。
不難看出 HTTP 協議的長連接和短連接,實質上就是 TCP 協議的長連接和短連接。
從 HTTP/1.1 開始默認使用長連接,會在響應頭加入 Connection:Keep-Alive
字段標識,如果需要斷開連接,需要由客戶端或者服務器提出斷開,使用 Connection:close
字段。
請求和響應
請求(request)總體從上向下包括:請求首行(請求方法、URL、協議版本)、請求頭(屬性是key:value形式、屬性一條一行)、空行、請求體(請求數據)
響應(response)總體從上向下包括:響應首行(協議版本、狀態碼和狀態描述)、響應頭(屬性是key:value形式、屬性一條一行)、空行、響應體(響應數據)
請求方法:
HTTP 1.0 定義三種請求方法:GET、POST、HEAD
HTTP 1.1 又增加了六種請求方法:OPTIONS、PUT、PATCH、DELETE、TRACE、CONNECT
方法 | 簡述 | |
---|---|---|
1 | GET | 請求指定的頁面信息,並返回實體主體。當前網絡請求中,絕大部分使用的是 GET 方法。在 RESTful 風格中常用作查詢。 |
2 | HEAD | 類似於 GET 請求,只不過返回的響應中沒有具體的內容,用於獲取報頭、確認 URL 的有效性以及資源更新的日期等等。。 |
3 | POST | 向指定資源提交數據進行處理請求(例如提交表單或者上傳文件)。數據被包含在請求體中。POST 請求可能會導致新的資源的建立和/或已有資源的修改。在 RESTful 風格中常用作添加。 |
4 | PUT | 從客戶端向服務器傳送的數據取代指定的文檔的內容。由於自身不帶驗證機制,任何人都可以上傳文件,因此存在安全性問題。在 RESTful 風格中常用作更新,但是隻能完全替代原始資源。 |
5 | DELETE | 請求服務器刪除指定的資源,並且同樣不帶驗證機制。在 RESTful 風格中常用作刪除。 |
6 | CONNECT | HTTP/1.1 協議中預留給能夠將連接改爲管道方式的代理服務器。使用 SSL(安全套接字) 和 TLS(傳輸層安全) 協議把通信內容加密後經網絡隧道傳輸。 |
7 | OPTIONS | 允許客戶端查看服務器的性能,查詢指定的 URL 能夠支持的方法,會返回形如 Allow: GET, POST, HEAD, OPTIONS 這樣的內容。 |
8 | TRACE | 回顯服務器收到的請求,主要用於測試或診斷。服務器會將通信路徑返回給客戶端,發送請求時,可以在 Max-Forwards 字段填入數值,每經過一個服務器就 -1 ,當數值爲 0 就停止傳輸。但是 TRACE 容易受到 XST 攻擊(跨站追蹤)。 |
9 | PATCH | 是對 PUT 方法的補充,用來對已知資源進行局部更新 。在 RESTful 風格中常用作資源更新,允許部分更新。 |
GET 和 POST 方法的區別?
- 在客戶端 GET 方法通過 URL 提交數據,所以只支持 ASCII 碼,所以 GET 參數中如果出現中文需要先進行編碼,而 POST 方法提交數據在報文中,支持多種標準字符集。
- GET 方法提交的數據大小瀏覽器有限制,Post 沒有。
- GET 方法時冪等的,同樣的請求被執行多次效果是一樣的,服務器狀態也是一樣的(統計功能除外),POST 方法是非冪等的。
- GET 請求可以被瀏覽器主動緩存,而 POST 不會,除非手動設置。
- GET 請求發送一個數據包 header 和 data一起發送出去,POST 請求先發送 header ,服務器響應 100 Continue,瀏覽器再發送 data。
HTTP 首部字段
不需要牢記,只是作爲字典進行查閱。
通用首部字段
首部字段名 | 說明 |
---|---|
Cache-Control | 控制緩存的行爲 |
Connection | 控制不再轉發給代理的首部字段、管理持久連接 |
Date | 創建報文的日期時間 |
Pragma | 報文指令 |
Trailer | 報文末端的首部一覽 |
Transfer-Encoding | 指定報文主體的傳輸編碼方式 |
Upgrade | 升級爲其他協議 |
Via | 代理服務器的相關信息 |
Warning | 錯誤通知 |
請求首部字段
首部字段名 | 說明 |
---|---|
Accept | 用戶代理可處理的媒體類型 |
Accept-Charset | 優先的字符集 |
Accept-Encoding | 優先的內容編碼 |
Accept-Language | 優先的語言(自然語言) |
Authorization | Web 認證信息 |
Expect | 期待服務器的特定行爲 |
From | 用戶的電子郵箱地址 |
Host | 請求資源所在服務器 |
If-Match | 比較實體標記(ETag) |
If-Modified-Since | 比較資源的更新時間 |
If-None-Match | 比較實體標記(與 If-Match 相反) |
If-Range | 資源未更新時發送實體 Byte 的範圍請求 |
If-Unmodified-Since | 比較資源的更新時間(與 If-Modified-Since 相反) |
Max-Forwards | 最大傳輸逐跳數 |
Proxy-Authorization | 代理服務器要求客戶端的認證信息 |
Range | 實體的字節範圍請求 |
Referer | 對請求中 URI 的原始獲取方 |
TE | 傳輸編碼的優先級 |
User-Agent | HTTP 客戶端程序的信息 |
響應首部
首部字段名 | 說明 |
---|---|
Accept-Ranges | 是否接受字節範圍請求 |
Age | 推算資源創建經過時間 |
ETag | 資源的匹配信息 |
Location | 令客戶端重定向至指定 URI |
Proxy-Authenticate | 代理服務器對客戶端的認證信息 |
Retry-After | 對再次發起請求的時機要求 |
Server | HTTP 服務器的安裝信息 |
Vary | 代理服務器緩存的管理信息 |
WWW-Authenticate | 服務器對客戶端的認證信息 |
實體首部字段
首部字段名 | 說明 |
---|---|
Allow | 資源可支持的 HTTP 方法 |
Content-Encoding | 實體主體適用的編碼方式 |
Content-Language | 實體主體的自然語言 |
Content-Length | 實體主體的大小 |
Content-Location | 替代對應資源的 URI |
Content-MD5 | 實體主體的報文摘要 |
Content-Range | 實體主體的位置範圍 |
Content-Type | 實體主體的媒體類型 |
Expires | 實體主體過期的日期時間 |
Last-Modified | 資源的最後修改日期時間 |
響應狀態碼
狀態碼 | 說明 |
---|---|
100 Continue | 服務器收到請求,請求者可以繼續發送請求或忽略這個響應 |
200 OK | 請求正常處理完成 |
201 Created | 已創建了新資源 |
202 Accepted | 服務器已接受並處理請求,但還未處理完畢 |
204 No Content | 請求已經處理成功,但是返回的響應報文 |
300 Redirection | 重定向 |
301 Moved Permanently | 永久性重定向,返回信息會包含新的 URL ,之後的請求都應使用新的 URL |
302 Found | 臨時性重定向,之後的請求應該繼續使用原本的 URL |
400 Bad Request | 客戶端請求錯誤 |
401 Unauthorized | 請求未授權,需要身份認證 |
403 Forbidden | 服務器拒絕執行此請求 |
404 Not Found | 服務器無法找到請求資源 |
405 Method Not Allowed | 請求方法不允許 |
500 Internal Server Failed | 服務器內部錯誤 |
501 Not Implemented | 服務器不支持請求的功能 |
502 Bad Gateway | 網關錯誤,從上游服務器收到了一個無效響應 |
503 Service Unavailable | 服務器超載或者宕機 |
504 Gateway Timeout | 網關超時 |
505 HTTP Version not supported | 服務器不支持請求的HTTP協議版本 |
Cookie 和 Session 的選擇
- Cookie 只能存儲 ASCII 碼字符串,Session 可以存儲任何類型的數據,因此考慮數據複雜性時首選 Session。
- Cookie 存儲在客戶端,容易被查看和竊取後發生 Cookie 欺騙,而 Session 存儲在服務器,因此考慮數據安全性時首選 Session。
- Session 會在服務器存活一段時間,如果是大流量網站,Session 進行存儲的開銷非常大,因此考慮減輕服務器性能壓力時可以選擇 Cookie。
- 很多瀏覽器對 Cookie 的大小和數量都存在限制,而 Session 不會被瀏覽器限制。
當客戶端禁用了 Cookie ,此時無法用 Cookie 保存信息,只能使用 Session;而且 SessionID 也無法存放在 Cookie 中,針對這點一般可以採用 URL 重寫,將 SessionID 作爲 URL 的參數進行傳遞、或者在頁面中使用一個隱藏表單,用於傳輸 SessionID。
HTTPS
說好的 HTTP 和 HTTPS ,怎麼所有篇幅都是在說 HTTP?
其實不然,HTTPS 並非什麼新的協議,而是讓 HTTP 先和 SSL(安全套接字) 通信,再由 SSL 和 TCP 完成通信,也就是說 HTTPS 是使用了 SSL 手段加密的隧道進行通信的 HTTP 協議!
SSL 位於 HTTP 和 TCP 之間的協議,其內部有 TLS握手協議、TLS記錄協議,HTTPS 依然經由 HTTP進行通信,但是利用 TLS 來保證安全。在 osi 七層結構中,SSL 處於會話層、HTTP 處於應用層,在 TCP/IP 結構和五層結構中 SSL 和 HTTP 同屬於應用層。
通過使用 SSL ,HTTPS 具有了加密隧道(防竊聽)、認證(防僞造)、完整性保護(防篡改)的安全特效特性。
SSL:安全套接字,1994年網景公司設計,1995年發佈了 3.0 版本。
TLS:傳輸層安全性協議,IETF 在 SSL3.0 的基礎上設計的協議。
下面使用 TLS 進行表述。
TLS 工作流程
將 HTTP 所有傳輸的內容都經過了加密,加密採用對稱加密,但是這個對稱加密的祕鑰用服務器上的證書(公鑰)進行了非對稱加密確保這個祕鑰的傳輸安全。因此 HTTPS 消耗了更多的服務器資源,但是安全性較 HTTP 有了質的提升。
上圖就是 TLS 的四次握手大致流程,第二次握手之後,客戶端可以選擇去頒發 server 證書的 CA 驗證這個證書的有效性!
下面再從每次握手後 client 和 server 的狀態簡單闡述一下:
-
第一次握手,client[A]
server[A,B,選用的加密套件,公鑰pk和對應祕鑰]
-
第二次握手,client[A,B,server.crt(公鑰pk)]
server[A,B,選用的加密套件,公鑰pk和對應祕鑰]
server 告知 client ,hello 階段完成了
-
第三次握手,client[A,B,C,server.crt(公鑰pk),Sesstion Secret]
server[A,B,C1,C,選用的加密套件,公鑰pk和對應祕鑰,Session Secret]
client 告知 server, 後續的通信都採用協商好的會話祕鑰和加密算法
這一步 server 需要驗證 F1、F2是否一致,爲了確認雙方會話祕鑰和加密算法一致。
-
第四次握手,client[A,B,C,server.crt(公鑰pk),Sesstion Secret]
server[A,B,C1,C,選用的加密套件,公鑰pk和對應祕鑰,Session Secret]
server告知 client , 後續的通信都採用協商好的會話祕鑰和加密算法
這一步 client 需要驗證 F3和原始明文數據是否一致,爲了確認 server 生成的會話祕鑰和採用的加密算法是否正確。
注意三點:
- 生成 Session Secret 需要三個隨機數的明文。
- 服務器證書中包含着服務器非對稱加密的密鑰對中的公鑰,私鑰只有服務器知道。
- server 證書中的公鑰只用來在協商祕鑰時加密會話祕鑰中的參數。
本人菜鳥,有錯誤請告知,感激不盡!
更多題解和源碼:github