URI 包含 URL 和 URN。
客戶端發送的 請求報文 第一行為請求行,包含了方法欄位。
獲取資源
當前網路請求中,絕大部分使用的是 GET 方法。
獲取報文首部
和 GET 方法類似,但是不返回報文實體主體部分。
主要用於確認 URL 的有效性以及資源更新的日期時間等。
傳輸實體主體
POST 主要用來傳輸數據,而 GET 主要用來獲取資源。
更多 POST 與 GET 的比較請見第九章。
上傳文件
由於自身不帶驗證機制,任何人都可以上傳文件,因此存在安全性問題,一般不使用該方法。
PUT /new.html HTTP/1.1 Host: example.com Content-type: text/html Content-length: 16
<p>New File</p>
對資源進行部分修改
PUT 也可以用於修改資源,但是隻能完全替代原始資源,PATCH 允許部分修改。
PATCH /file.txt HTTP/1.1 Host: www.example.com Content-Type: application/example If-Match: "e0023aa4e" Content-Length: 100
[description of changes]
刪除文件
與 PUT 功能相反,並且同樣不帶驗證機制。
DELETE /file.html HTTP/1.1
查詢支持的方法
查詢指定的 URL 能夠支持的方法。
會返回 Allow: GET, POST, HEAD, OPTIONS 這樣的內容。
Allow: GET, POST, HEAD, OPTIONS
要求在與代理伺服器通信時建立隧道
使用 SSL(Secure Sockets Layer,安全套接層)和 TLS(Transport Layer Security,傳輸層安全)協議把通信內容加密後經網路隧道傳輸。
CONNECT www.example.com:443 HTTP/1.1
追蹤路徑
伺服器會將通信路徑返回給客戶端。
發送請求時,在 Max-Forwards 首部欄位中填入數值,每經過一個伺服器就會減 1,當數值為 0 時就停止傳輸。
通常不會使用 TRACE,並且它容易受到 XST 攻擊(Cross-Site Tracing,跨站追蹤)。
伺服器返回的 響應報文 中第一行為狀態行,包含了狀態碼以及原因短語,用來告知客戶端請求的結果。
狀態碼類別含義1XXInformational(信息性狀態碼)接收的請求正在處理2XXSuccess(成功狀態碼)請求正常處理完畢3XXRedirection(重定向狀態碼)需要進行附加操作以完成請求4XXClient Error(客戶端錯誤狀態碼)伺服器無法處理請求5XXServer Error(伺服器錯誤狀態碼)伺服器處理請求出錯
有 4 種類型的首部欄位:通用首部欄位、請求首部欄位、響應首部欄位和實體首部欄位。
各種首部欄位及其含義如下(不需要全記,僅供查閱):
首部欄位名說明Cache-Control控制緩存的行為Connection控制不再轉發給代理的首部欄位、管理持久連接Date創建報文的日期時間Pragma報文指令Trailer報文末端的首部一覽Transfer-Encoding指定報文主體的傳輸編碼方式Upgrade升級為其他協議Via代理伺服器的相關信息Warning錯誤通知
首部欄位名說明Accept用戶代理可處理的媒體類型Accept-Charset優先的字符集Accept-Encoding優先的內容編碼Accept-Language優先的語言(自然語言)AuthorizationWeb 認證信息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-AgentHTTP 客戶端程序的信息
首部欄位名說明Accept-Ranges是否接受位元組範圍請求Age推算資源創建經過時間ETag資源的匹配信息Location令客戶端重定向至指定 URIProxy-Authenticate代理伺服器對客戶端的認證信息Retry-After對再次發起請求的時機要求ServerHTTP 伺服器的安裝信息Vary代理伺服器緩存的管理信息WWW-Authenticate伺服器對客戶端的認證信息
首部欄位名說明Allow資源可支持的 HTTP 方法Content-Encoding實體主體適用的編碼方式Content-Language實體主體的自然語言Content-Length實體主體的大小Content-Location替代對應資源的 URIContent-MD5實體主體的報文摘要Content-Range實體主體的位置範圍Content-Type實體主體的媒體類型Expires實體主體過期的日期時間Last-Modified資源的最後修改日期時間
當瀏覽器訪問一個包含多張圖片的 HTML 頁面時,除了請求訪問的 HTML 頁面資源,還會請求圖片資源。如果每進行一次 HTTP 通信就要新建一個 TCP 連接,那麼開銷會很大。
長連接只需要建立一次 TCP 連接就能進行多次 HTTP 通信。
Connection : close
Connection : Keep-Alive
默認情況下,HTTP 請求是按順序發出的,下一個請求只有在當前請求收到響應之後才會被發出。由於受到網路延遲和帶寬的限制,在下一個請求被發送到伺服器之前,可能需要等待很長時間。
流水線是在同一條長連接上連續發出請求,而不用等待響應返回,這樣可以減少延遲。
HTTP 協議是無狀態的,主要是為了讓 HTTP 協議儘可能簡單,使得它能夠處理大量事務。HTTP/1.1 引入 Cookie 來保存狀態信息。
Cookie 是伺服器發送到用戶瀏覽器並保存在本地的一小塊數據,它會在瀏覽器之後向同一伺服器再次發起請求時被攜帶上,用於告知服務端兩個請求是否來自同一瀏覽器。由於之後每次請求都會需要攜帶 Cookie 數據,因此會帶來額外的性能開銷(尤其是在移動環境下)。
Cookie 曾一度用於客戶端數據的存儲,因為當時並沒有其它合適的存儲辦法而作為唯一的存儲手段,但現在隨著現代瀏覽器開始支持各種各樣的存儲方式,Cookie 漸漸被淘汰。新的瀏覽器 API 已經允許開發者直接將數據存儲到本地,如使用 Web storage API(本地存儲和會話存儲)或 IndexedDB。
伺服器發送的響應報文包含 Set-Cookie 首部欄位,客戶端得到響應報文後把 Cookie 內容保存到瀏覽器中。
HTTP/1.0 200 OK Content-type: text/html Set-Cookie: yummy_cookie=choco Set-Cookie: tasty_cookie=strawberry
[page content]
客戶端之後對同一個伺服器發送請求時,會從瀏覽器中取出 Cookie 信息並通過 Cookie 請求首部欄位發送給伺服器。
GET /sample_page.html HTTP/1.1 Host: www.example.org Cookie: yummy_cookie=choco; tasty_cookie=strawberry
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
Domain 標識指定了哪些主機可以接受 Cookie。如果不指定,默認為當前文檔的主機(不包含子域名)。如果指定了 Domain,則一般包含子域名。例如,如果設置 Domain=http://mozilla.org,則 Cookie 也包含在子域名中(如 http://developer.mozilla.org)。
Path 標識指定了主機下的哪些路徑可以接受 Cookie(該 URL 路徑必須存在於請求 URL 中)。以字元 %x2F ("/") 作為路徑分隔符,子路徑也會被匹配。例如,設置 Path=/docs,則以下地址都會匹配:
瀏覽器通過 document.cookie 屬性可創建新的 Cookie,也可通過該屬性訪問非 HttpOnly 標記的 Cookie。
document.cookie
document.cookie = "yummy_cookie=choco"; document.cookie = "tasty_cookie=strawberry"; console.log(document.cookie);
標記為 HttpOnly 的 Cookie 不能被 JavaScript 腳本調用。跨站腳本攻擊 (XSS) 常常使用 JavaScript 的 document.cookie API 竊取用戶的 Cookie 信息,因此使用 HttpOnly 標記可以在一定程度上避免 XSS 攻擊。
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly
標記為 Secure 的 Cookie 只能通過被 HTTPS 協議加密過的請求發送給服務端。但即便設置了 Secure 標記,敏感信息也不應該通過 Cookie 傳輸,因為 Cookie 有其固有的不安全性,Secure 標記也無法提供確實的安全保障。
除了可以將用戶信息通過 Cookie 存儲在用戶瀏覽器中,也可以利用 Session 存儲在伺服器端,存儲在伺服器端的信息更加安全。
Session 可以存儲在伺服器上的文件、資料庫或者內存中。也可以將 Session 存儲在 Redis 這種內存型資料庫中,效率會更高。
使用 Session 維護用戶登錄狀態的過程如下:
應該注意 Session ID 的安全性問題,不能讓它被惡意攻擊者輕易獲取,那麼就不能產生一個容易被猜到的 Session ID 值。此外,還需要經常重新生成 Session ID。在對安全性要求極高的場景下,例如轉賬等操作,除了使用 Session 管理用戶狀態之外,還需要對用戶進行重新驗證,比如重新輸入密碼,或者使用簡訊驗證碼等方式。
此時無法使用 Cookie 來保存用戶信息,只能使用 Session。除此之外,不能再將 Session ID 存放到 Cookie 中,而是使用 URL 重寫技術,將 Session ID 作為 URL 的參數進行傳遞。
HTTP 有以下安全性問題:
HTTPS 並不是新協議,而是讓 HTTP 先和 SSL(Secure Sockets Layer)通信,再由 SSL 和 TCP 通信,也就是說 HTTPS 使用了隧道進行通信。
通過使用 SSL,HTTPS 具有了加密(防竊聽)、認證(防偽裝)和完整性保護(防篡改)。
對稱密鑰加密(Symmetric-Key Encryption),加密和解密使用同一密鑰。
非對稱密鑰加密,又稱公開密鑰加密(Public-Key Encryption),加密和解密使用不同的密鑰。
公開密鑰所有人都可以獲得,通信發送方獲得接收方的公開密鑰之後,就可以使用公開密鑰進行加密,接收方收到通信內容後使用私有密鑰解密。
非對稱密鑰除了用來加密,還可以用來進行簽名。因為私有密鑰無法被其他人獲取,因此通信發送方使用其私有密鑰進行簽名,通信接收方使用發送方的公開密鑰對簽名進行解密,就能判斷這個簽名是否正確。
HTTPS 採用混合的加密機制,使用非對稱密鑰加密用於傳輸對稱密鑰來保證傳輸過程的安全性,之後使用對稱密鑰加密進行通信來保證通信過程的效率。(下圖中的 Session Key 就是對稱密鑰)
推薦閱讀: