參考博客:https://cloud.tencent.com/developer/article/2183902
一、HTTP協議概述
HTTP(HyperText Transfer Protocol) 即 超文本傳輸協議,它是一種用于分布式、協作式和超媒體信息系統的應用層協議。HTTP 是萬維網(www)的數據通信的基礎。
HTTP 作為一個應用層協議,它由請求和響應兩部分構成,是一個標準的個客戶端和服務器模型,它的主要特點:支持客戶端/服務器模型、簡單快速、靈活、無連接、無狀態
1、簡單快速
客戶端向服務器發送服務請求時,只需傳路徑和請求方法。請求方法包括有 GET、POST、HEAD 等。每種方法規定了客戶端與服務器聯系的不同類型。由于 HTTP 協議簡單,使得 HTTP 服務器的程序規模小,因而通信速度很快
2、靈活
HTTP 允許傳輸任意類型的數據對象,正在傳輸的類型由 Content-Type 加以標記,最常見的 4 種 Content-Type 的取值如下:
- application/x-www-form-urlencoded(常見的 form 提交):最常見 POST 提交數據的方式。瀏覽器的原生 form 表單,如果不設置 enctype 屬性,那么最終就會以此鐘方式提交數據
- multipart/form-data(文件提交):另一種非常常見的 POST 數據提交的方式。我們在使用表單上傳文件時,必須讓 form 的 enctyped 等于這個值
- application/json(提交 json 格式的數據):現在越來越多的人把它作為請求頭,用來告訴服務端消息主體是序列化后的 JSON 字符串。由于 JSON 規范的流行,除了低版本 IE 之外的各大瀏覽器都原生支持 JSON.stringify,服務端語言也都有處理 JSON 的函數,使用 JSON 不會遇上什么麻煩
- text/xml(提交 xml 格式的數據) :XML-RPC(XML Remote Procedure Call)。它是一種使用 HTTP 作為傳輸協議,XML 作為編碼方式的遠程調用規范
3、無連接
無連接的含義是限制每次連接只處理一個請求,服務器處理完客戶端的請求,然后響應,并收到應答之后,就斷開連接,這種方式可以節省傳輸時間。
4、無狀態
HTTP 協議是無狀態協議,無狀態是指協議對于事務處理沒有記憶能力,這種方式的一個壞處就是,如果后續的處理需要用到之前的信息,則必須要重傳,這樣就導致了每次連接傳輸的數據量增大。好處就是,如果后續的連接不需要之前提供的信息,響應就會比較快。而為了解決 HTTP 的無狀態特性,出現了 Cookie 和 Session 技術.
二、HTTP報文結構
-
你也許對 TCP/UDP 的報?格式有所了解,拿 TCP 報?來舉例,它在實際要傳輸的數據之前附加了?個20 字節的頭部數據,存儲 TCP 協議必須的額外信息,例如發送?的端?號、接收?的端?號、包序號、標志位等等。
-
有了這個附加的 TCP 頭,數據包才能夠正確傳輸,到了?的地后把頭部去掉,就可以拿到真正的數據。
HTTP 協議也是與 TCP/UDP 類似,同樣也需要在實際傳輸的數據前附加?些頭數據,不過與 TCP/UDP不同的是,它是?個“純?本”的協議,所以頭數據都是 ASCII 碼的?本,可以很容易地??眼閱讀,不?借助程序解析也能夠看懂。
HTTP 協議的請求報?和響應報?的結構基本相同,由三?部分組成:
- 起始?(start line):描述請求或響應的基本信息;
- 頭部字段集合(header):使? key-value 形式更詳細地說明報?;
- 消息正?(entity):實際傳輸的數據,它不?定是純?本,可以是圖?、視頻等?進制數據。
-
這其中前兩部分起始?和頭部字段經常?合稱為“請求頭”或“響應頭”,消息正??稱為“實體”,但與“header”對應,很多時候就直接稱為“body”。
-
HTTP 協議規定報?必須有 header,但可以沒有 body,?且在 header 之后必須要有?個“空?”,也就是“CRLF”,?六進制的“0D0A”。
所以,?個完整的 HTTP 報?就像是下圖的這個樣?,注意在 header 和 body 之間有?個“空?”
下面是一個HTTP請求報文:
-
在這個瀏覽器發出的請求報??,第??“GET / HTTP/1.1”就是請求?,?后?的“Host”“Connection”等等都屬于 header,報?的最后是?個空??結束,沒有 body。
-
在很多時候,特別是瀏覽器發送 GET 請求的時候都是這樣,HTTP 報?經常是只有 header ?沒 body。
2.1 請求?
了解了 HTTP 報?的基本結構后,我們來看看請求報??的起始?也就是請求?(request line),它簡要地描述了客戶端想要如何操作服務器端的資源
請求?由三部分構成:
- 請求?法:是?個動詞,如 GET/POST,表示對資源的操作;
- 請求?標:通常是?個 URI,標記了請求?法要操作的資源;
- 版本號:表示報?使?的 HTTP 協議版本。
這三個部分通常使?空格(space)來分隔,最后要? CRLF 換?表示結束。(圖示SP代表空格)
下面具體說明GET的請求行
GET / HTTP/1.1\r\n
GET /live/livestream.m3u8 HTTP/1.1\r\n
-
在這個請求??,“GET”是請求?法,“/”是請求?標,“HTTP/1.1”是版本號,把這三部分連起來,意思就是“服務器你好,我想獲取?站根?錄下的默認?件,我?的協議版本號是 1.1,請不要? 1.0 或者 2.0回復我。
-
別看請求?就??,貌似很簡單,其實這??的“講究”是?常多的,尤其是前?的請求?法和請求?標,組合起來變化多端,后?我還會詳細介紹。
2.2 狀態?
看完了請求?,我們再看響應報??的起始?,在這?它不叫“響應?”,?是叫“狀態?”(statusline),意思是服務器響應的狀態。
?起請求?來說,狀態?要簡單?些,同樣也是由三部分構成:
- 版本號:表示報?使?的 HTTP 協議版本;
- 狀態碼:?個三位數,?代碼的形式表示處理的結果,?如 200 是成功,500 是服務器錯誤;
- 原因:作為數字狀態碼補充,是更詳細的解釋?字,幫助?理解原因。
下面是一個HTTP響應報文
HTTP/1.1 200 OK\r\n
意思就是:“瀏覽器你好,我已經處理完了你的請求,這個報?使?的協議版本號是 1.1,狀態碼是 200,?切 OK。”
?另?個“GET /favicon.ico HTTP/1.1”的響應報?狀態?是:
HTTP/1.1 404 Not Found
翻譯成?話就是:“抱歉啊瀏覽器,剛才你的請求收到了,但我沒找到你要的資源,錯誤代碼是 404,接下來的事情你就看著辦吧。”
2.3 頭部字段
請求?或狀態?再加上頭部字段集合就構成了 HTTP 報??完整的請求頭或響應頭
請求頭和響應頭的結構是基本?樣的,唯?的區別是起始?,所以我把請求頭和響應頭?的字段放在?起介紹。
-
頭部字段是 key-value 的形式,key 和 value 之間?“:”分隔,最后? CRLF 換?表示字段結束。?如在“Host: 127.0.0.1”這??? key 就是“Host”,value 就是“127.0.0.1”。
-
HTTP 頭字段?常靈活,不僅可以使?標準?的 Host、Connection 等已有頭,也可以任意添加?定義頭,這就給 HTTP 協議帶來了?限的擴展可能。
不過使?頭字段需要注意下??點:
-
字段名不區分??寫,例如“Host”也可以寫成“host”,但?字??寫的可讀性更好;
-
字段名?不允許出現空格,可以使?連字符“-”,但不能使?下劃線“_”。例如,“test-name”是合法的字段名,?“test name”“test_name”是不正確的字段名;
-
字段名后?必須緊接著“:”,不能有空格,?“:”后的字段值前可以有多個空格;
-
字段的順序是沒有意義的,可以任意排列不影響語義;
-
字段原則上不能重復,除?這個字段本身的語義允許,例如 Set-Cookie。
?wireshark抓包的分析
請求報文
響應報文
2.4 常?頭字段
HTTP 協議規定了?常多的頭部字段,實現各種各樣的功能,但基本上可以分為四?類:
- 通?字段:在請求頭和響應頭?都可以出現;
- 請求字段:僅能出現在請求頭?,進?步說明請求信息或者額外的附加條件;
- 響應字段:僅能出現在響應頭?,補充說明響應報?的信息;
- 實體字段:它實際上屬于通?字段,但專?描述 body 的額外信息。
對 HTTP 報?的解析和處理實際上主要就是對頭字段的處理,理解了頭字段也就理解了 HTTP 報?。
2.4.1 User-Agent
-
User-Agent是請求字段,只出現在請求頭?。它使??個字符串來描述發起 HTTP 請求的客戶端,服務器可以依據它來返回最合適此瀏覽器顯示的??。
-
但由于歷史的原因,User-Agent ?常混亂,每個瀏覽器都?稱是“Mozilla”“Chrome”“Safari”,企圖使?這個字段來互相“偽裝”,導致 User-Agent 變得越來越?,最終變得毫?意義。
-
不過有的?較“誠實”的爬?會在 User-Agent ??“spider”標明??是爬?,所以可以利?這個字段實現簡單的反爬?策略。
2.4.2 Accept
- Accept是請求字段,代表客戶端希望接受的數據類型。
- ?如Accept:text/xml(application/json);代表客戶端希望接受的數據類型是xml(json )類型;
- ?如Accept: */*則說明客戶端接收所有類型的數據。
2.4.3 Host
-
?先要說的是Host字段,它屬于請求字段,只能出現在請求頭?,它同時也是唯??個 HTTP/1.1 規范?要求必須出現的字段,也就是說,如果請求頭?沒有 Host,那這就是?個錯誤的報?。
-
Host 字段告訴服務器這個請求應該由哪個主機來處理,當?臺計算機上托管了多個虛擬主機的時候,服務器端就需要? Host 字段來選擇,有點像是?個簡單的“路由重定向”。
-
例如我們的試驗環境,在 127.0.0.1 上有三個虛擬主機:“www.chrono.com”“www.metroid.net”和“origin.io”。那么當使?域名的?式訪問時,就必須要?Host 字段來區分這三個 IP 相同但域名不同的?站,否則服務器就會找不到合適的虛擬主機,?法處理。
2.4.4 Range
-
Range是請求字段。
-
?如Range: bytes=5001-10000 對于只需獲資源的范圍請求,包含?部字段 Range 即可告知服務器資源的指定范圍。上?的示例表示請求獲取從第 5001 字節到第 10000 字節的資源。
-
?如Range: bytes=0- 則是請求所有的數據。
-
接收到附帶 Range ?部字段請求的服務器,會在處理請求之后返回狀態碼為 206 Partial Content 的響應。?法處理該范圍請求時,則會返回狀態碼 200 OK 的響應及全部資源。
2.4.5 Connection
管理持久連接
- close 斷開連接
- HTTP/1.1版本的默認連接都是持久連接。為此,客戶端會在持久連接上連續發送請求。當服務器端想明確斷開連接時,則指定 Connection ?部字段的值為 close 。
Connection: close
- Keep-Alive 保持連接
-
HTTP/1.1 之前的版本的默認連接都是?持久連接。為此,如果想在舊版本的HTTP協議上維持持續連接,則需要指定 Connection ?部字段的值為 keep-alive 。
-
在客戶單發送請求給服務器時,攜帶此參數和值,服務器也會加上字段和值進?返回響應。
Connection: keep-alive
http是?個?狀態的?向連接的協議。
-
http?狀態:?狀態協議是指http協議本身對于事務處理沒有記憶功能,服務器不知道瀏覽器的狀態。通俗的即使你登錄了,去訪問同?個?站的不同??,服務器都不會知道你是誰,如果需要記錄登錄?戶的信息,?戶操作,?戶?為等數據需要使?cookie或session來存儲。
-
keep-alive:從HTTP/1.1起,瀏覽器默認都開啟了Keep-Alive,保持連接特性,客戶端和服務器都能選擇隨時關閉連接,則請求頭中為connection:close。簡單地說,當?個??打開完成后,客戶端和服務器之間?于傳輸HTTP數據的TCP連接不會關閉,如果客戶端再次訪問這個服務器上的??,會繼續使?這?條已經建?的TCP連接。但是Keep-Alive不會永久保持連接,它有?個保持時間,可以在不同的服務器軟件(如Apache)中設定這個時間。
-
誤解:?狀態不代表HTTP不能保持TCP連接,更不能代表HTTP使?的是UDP協議(?連接)。即使http在?狀態下,只要客戶端和服務器的頭部信息connection:keep-alive,則在有效期內他們使?同?條TCP連接。
2.4.6 Date
- Date字段是?個通?字段,但通常出現在響應頭?,表示 HTTP 報?創建的時間,客戶端可以使?這個時間再搭配其他字段決定緩存策略。
2.4.7 Server
-
Server字段是響應字段,只能出現在響應頭?。它告訴客戶端當前正在提供 Web 服務的軟件名稱和版本號, Server 字段也不是必須要出現的,因為這會把服務器的?部分信息暴露給外界,如果這個版本恰好存在 bug,那么?客就有可能利? bug 攻陷服務器。所以,有的?站響應頭?要么沒有這個字段,要么就給出?個完全?關的描述信息。
-
?如 GitHub,它的 Server 字段?就看不出是使?了 Apache 還是 Nginx,只是顯示為“GitHub.com”。
再?如srs流媒體服務器的響應
Server: SRS/3.0.141(OuXuli)\r\n
2.4.8 Content-Type
- Content-Type是實體字段,表發送端(客戶端|服務器)發送的實體數據的數據類型。?如:ContentType:text/html(application/json) ; 代表發送端發送的數據格式是html(json)。
2.4.9 Content-Length
- 實體字段?要說的?個是Content-Length,它表示報?? body 的?度,也就是請求頭或響應頭空?后?數據的?度。服務器看到這個字段,就知道了后續有多少數據,可以直接接收。如果沒有這個字段,那么 body 就是不定?的,需要使? chunked ?式分段傳輸。
更多資料:https://github.com/0voice