HTTP
- 🍉簡介
- 🍉抓包工具
- 🍉報文結構
- 🍌請求
- 🍌響應
- 🍌URL
- 🥝URL encode
- 🍌方法
- 🍌報文字段
- 🥝Host
- 🥝Content-Length & Content-Type
- 🥝User-Agent(UA)
- 🥝Referer
- 🥝Cookie
- 🍉狀態碼
- 🍌類別
- 🍌常見狀態碼
🍉簡介
HTTP 協議全稱為超文本傳輸協議,超文本比文本更加強大,它不僅包含字符串,還可以攜帶一些圖片、特殊格式等
HTTP 最主要的應用場景就是網站。瀏覽器和服務器、客戶端和服務器之間傳輸數據的協議,很可能就是 HTTP
🍉抓包工具
抓包工具本質上是一個代理程序,能夠獲取到網絡上傳輸的數據并顯示出來,從而給程序員提供一些參考,在后面介紹 HTTP 報文格式的過程中,會頻繁用到抓包工具,這里我們使用 fiddler,它專注于 HTTP 的抓包
打開一個網站,瀏覽器和服務器之間會進行多次 HTTP 交互,其中第一次交互拿到的是這個頁面的 html
選中這個請求并雙擊,可以看到明細:
點擊 RAW,可以查看 HTTP 請求的原始數據
下面是請求的原始數據
再來看下響應的原始數據
為了節省帶寬,一般響應數據會被壓縮,對上述響應解壓縮得到:
🍉報文結構
🍌請求
HTTP 請求包含 4 個部分
- 首行
- 請求頭:由若干個鍵值對組成,每個鍵值對占一行,鍵和值之間使用 : 分割
- 空行:請求頭的結束標記
- 正文(body):http 的
載荷
部分,有的 http 請求有 body,有的沒有
🍌響應
HTTP 響應的基本格式也是分為四個部分
- 首行
2. 響應頭:這里是按照鍵值對的形式來組織內容
3. 空行
4. 響應正文(body):響應的載荷是 html
🍌URL
URL 全稱為唯一資源定位符,用來描述一個網絡上資源的位置
一個 URL 的完整結構如下:
🥝URL encode
query string(查詢字符串)里是自定義的鍵值對,而在 URL 中,有些特殊符號,比如 / : ? @ 等都是有特定的含義,如果 query string 中也包含同樣的符號,可能會使服務器 / 瀏覽器解析失敗,比較靠譜的方法就是對上述符號進行轉義(就像 C語言中用 printf 打印一些特殊符號一樣,需要轉義)。
除了這些特殊符號,漢字也要進行轉義,因為漢字的 utf8 / gbk 等編碼值中可能某個字節恰好和某個符號的 ASCII 碼值一致
下面舉個例子,比如搜索 C++:
🍌方法
有兩個典型的使用 POST 的場景:登錄和上傳
以登錄為例,在一個網站輸入賬號密碼登錄后抓包得到的數據報的 body:
這里有一個比較經典的面試題:
GET 和 POST 有什么區別
GET 和 POST 本質上沒有區別。使用 GET 的場景也可以替換為 POST;使用 POST 的場景也可以替換為 GET。這取決于代碼是怎么寫的,尤其是服務器和客戶端都是自己實現的情況下
但是這兩者在使用習慣上還是有區別的:
- GET 習慣于把數據放到 URL 的 query string 中;POST 習慣于把數據放到 body 中
- 語義上的區別。標準文檔中,GET 的語義是用來獲取數據;POST 的語義是給服務器傳輸數據。當然實際使用并不拘泥于上述要求
- 關于冪等性。標準文檔中建議 GET 請求實現成冪等的;POST 則沒有要求。當然 GET 在實際開發中也不一定得實現成冪等
這里的“冪等”源于數學術語,如果每次輸入的內容一定,輸出的結果也一定,那就是冪等;反之,若輸入內容一定,但輸出不一定,則不是冪等。在計算機中,如果某個操作是冪等的,那就可以進行緩存
🍌報文字段
🥝Host
表示服務器主機的地址和端口
🥝Content-Length & Content-Type
這兩個字段分別表示 body 中數據的長度
和請求的 body 中的數據格式
HTTP 底層也是基于 TCP
。連續傳輸多個 HTTP 數據報的話,接收方這邊的接收緩沖區里就會積累多個包的數據,應用程序在讀取這些數據時需要明確包與包之間的邊界
。通過長度可以解決粘包問題
🥝User-Agent(UA)
UA 描述了操作系統和瀏覽器的信息,這兩個其實就是在描述用戶使用什么樣的設備上網
它里面包含了系統信息,這就可以判定系統是 PC 的系統,還是移動端的系統,此時可以根據這個信息來返回不同的頁面
比如在手機瀏覽器的設置中手動把 UA 修改為 PC 的 UA,那么就可以訪問電腦版的網頁了
🥝Referer
描述當前這個頁面從哪兒來,類似上層目錄,所以直接在瀏覽器輸入 URL 的路徑或從收藏夾中打開的網頁都是沒有 referer 的
🥝Cookie
Cookie 是報頭中一個非常重要的屬性,它本質上是瀏覽器本地持久化存儲數據
的機制
操作系統提供了 api 操作文件,瀏覽器作為電腦上的一個程序,可以調用這些 api 來讀寫本地磁盤文件。而瀏覽器上運行的網頁,理論上也是可以通過瀏覽器提供的 api 來讀寫本地文件,但是為了保證安全性,瀏覽器禁止這種做法,也就是說它沒有給網頁提供這樣的 api。不然有些不法分子搞一些惡意網站,你點進去之后它就會把你電腦上的文件刪掉,這樣勢必會造成巨大損失!
不過有些網站需要把一些信息保存到瀏覽器這邊,比如登錄界面需要保存用戶的身份信息。所以瀏覽器給網頁提供了這樣的 api:可以有限度地存儲數據,但不能隨意訪問文件系統
Cookie 就是一種經典的存儲數據的機制
,它將存儲的數據按照鍵值對的形式存儲起來,其中鍵值對是由程序員自定義的,和 query string 差不多,因此不同網站的 Cookie 都是不一樣的
HTTP 請求中的 Cookie 字段就是把本地存儲的 Cookie 信息發送到服務器。相應地,HTTP 響應中會有一個 Set-Cookie 字段,這個是服務器告訴瀏覽器要在本地保存哪些信息
通常在首次訪問 / 登錄成功之后服務器會把數據返回給瀏覽器,然后 Cookie 會以域名為維度
存儲在瀏覽器本地主機的硬盤上,比如瀏覽器訪問 Gitee,就有一組 Cookie,訪問 B 站,又有一組 Cookie,這些 Cookie 之間互不沖突,后續每次訪問服務器都會帶上對應網站的 Cookie
不同的客戶端保存的 Cookie 是不同的,即使是同一臺主機,使用不同的瀏覽器,Cookie 大概率也是不同的
Cookie 用途就是在客戶端保存數據,其中保存的數據最主要是用戶的身份標識,這樣服務器就可以通過標識來區分用戶。它一般不會保存其他業務數據,這些數據存在服務器,通過 Cookie 中的身份標識可以找到這些數據
有個典型的場景:在某個頁面登錄之后,下次登錄就不用再輸入賬號密碼,因為首次輸入賬密后這些信息就會保存在磁盤,下次進入網頁時就會先從本地讀取磁盤拿到賬密。發送 HTTP 請求后服務器收到 Cookie 中的用戶信息后就通過身份驗證了,所以不用再手動輸入賬密
補充:頁游中的賬號密碼等信息一般不是放在 Cookie 中的,因為瀏覽器保存的密碼都是明文密碼,放到 Cookie 中不安全
🍉狀態碼
🍌類別
🍌常見狀態碼
- 200 OK
打開 Fiddler,放眼望去基本都是 200,它表示請求已經成功處理
- 404 Not Found
這個也很常見,Not found 表示訪問的資源沒找到,此處的資源指的是URL 中的路徑
比如輸入一個不存在的網址:
-
403 Forbidden
表示請求的資源沒有權限訪問 -
405 Method Not Allowed
如果你的服務器只支持 GET 請求,但是你發了一個 POST 請求,那就會出現這個狀態碼 -
500 Internal Server Error
表示服務器內部錯誤,遇到這種情況可能是服務器掛了 -
504 Gateway Timeout
訪問服務器超時了,這可能是服務器掛了,也可能是網斷了 -
302 Move temporarily
臨時重定向,表示資源臨時移動到新的位置
。除了 302,301 也表示重定向,不過它是永久性的
。重定向的時間會影響瀏覽器的緩存,如果是永久性的,那么瀏覽器會把重定向的結果記錄下來,后續再次訪問就會直接訪問重定向的目標地址,不用多一次跳轉了;而如果是臨時性的,那就不太方便緩存了
重定向報文的響應中會有一個特殊的 header:Location,它描述了重定向的目標地址
在哪兒