HTTP 是什么?
Hyper Text Transfer Protocol 超文本傳輸協(xié)議,是一種 Client 和 Server 之間請求和應(yīng)答的標(biāo)準(zhǔn),目的是更高效的進(jìn)行網(wǎng)絡(luò)傳輸。
HTTP 工作方式
用戶最直觀的感受就是瀏覽器地址欄鍵入地址->回車->看到瀏覽器呈現(xiàn)的網(wǎng)頁,這個過程簡單的流程就是:
瀏覽器發(fā)送請求到服務(wù)器,服務(wù)器響應(yīng)請求,瀏覽器通過渲染引擎渲染網(wǎng)頁結(jié)果,渲染引擎也就是瀏覽器的內(nèi)核。

示例地址:https://twitter.com/shaddeen_/followers
shaddeen,是小眾音樂播放器 Loud 和 SmartPlayer 的作者。
所以在這個從按下回車到直觀看到界面的過程就簡單的概括為 3 步:
- 請求
- 響應(yīng)
- 渲染
在請求的過程中,瀏覽器地址欄的 URL 轉(zhuǎn)化成 HTTP 報文進(jìn)行發(fā)送,一個 URL 大致分為三個部分:
https/http: 協(xié)議類型、twitter.com 服務(wù)器地址和shaddeen_/followers 路徑(path)。
請求發(fā)送的形式就變成:
GET /shaddeen_/followers HTTP/1.1
Host: twitter.com
在這個過程中,兩個極其重要的角色也就出現(xiàn)了:Request 和 Response。
Request 報文格式
簡易的 Request 報文格式如下:
GET /shaddeen_/followers HTTP/1.1
Host: twitter.com
GET /shaddeen_/followers HTTP/1.1為一個請求行,分三個部分:
- GET 為 請求 method;
- /shaddeen_/followers 為 path,負(fù)責(zé)定位;
- HTTP/1.1 為 HTTP Version,現(xiàn)在絕大多數(shù)的瀏覽器的網(wǎng)頁顯示 HTTP 版本都是 1.1。
Host: twitter.com 為請求 Headers,可為多行(包括更多的內(nèi)容如 Content-Type: text/plain Content-Length: 240)。
另,請求可以加入 Body,可以加入實際的內(nèi)容,該內(nèi)容是服務(wù)器需要處理的。Body 和請求行中的 path 都是和服務(wù)器對接并需要服務(wù)器處理的,但是各自角色的定位并不一樣。
Response 報文格式
Response 的報文同樣也有 Headers 和 Body,相比 Request 無請求行,多了一個狀態(tài)行,例:
狀態(tài)行?
HTTP/1.1 200 OK
Headers?
content-type: application/json; charset=utf-8
cache-control: public, max-age=60, s-maxage=60
vary: Accept, Accept-Encoding
etag: W/"02fjsdarwr080823f"
content-encoding: gzip
Body?
[
name: "shaddeen_",
id: "2342242",
follow_list: [
...
]
...
]
HTTP/1.1 200 OK 亦分為三個部分:
- HTTP/1.1 HTTP 版本;
- 200 status code 狀態(tài)碼;
- OK status message 狀態(tài)信息。
這三部分的組合可以簡單地描述一次請求。
Request Method
- GET 獲取資源,無 body,簡單的來說就是從網(wǎng)上取東西;
- POST 增加或修改資源,有 body,要把修改的內(nèi)容放進(jìn) body 里給服務(wù)器進(jìn)行處理;
- PUT 修改資源, 有 body,它和 GET 有個共同的特點就是冪等(一個冪等操作的特點是其任意多次執(zhí)行所產(chǎn)生的影響均與一次執(zhí)行的影響相同,在這里指多次操作對于服務(wù)器沒有影響)的;
- DELETE 刪除資源,無 body,同樣具有冪等性;
- HEAD 幾乎和 GET 是一樣的,區(qū)別在于服務(wù)器返回內(nèi)容的時候不會返回 body,當(dāng)做下載功能的時候通常需要預(yù)先知道該文件有多大或更多的信息,此時 HEAD 通過請求會得到這些信息,然后再進(jìn)行一步處理。
Status Code
作用:對結(jié)果作出類型化描述(如「成功」、「未找到」)。
通常規(guī)范化的狀態(tài)碼有 5 類,分類是為了方便調(diào)試:
- 1xx: 臨時性消息,通常為 100 和 101。100,表示初始的請求已經(jīng)接受,客戶端可以接著進(jìn)行下面的請求,如上傳一個大文件,在試探性請求服務(wù)器的過程中,會把一些描述信息放進(jìn) Header 中與服務(wù)器溝通試探服務(wù)器是否接受,如服務(wù)器返回 100 則客戶端可以進(jìn)行下面的操作。101 表示服務(wù)器回應(yīng)客戶端「支持 HTTP/2.0」,此時客戶端下一次的請求就可以切換為為 HTTP/2.0,當(dāng)不支持 HTTP/2.0 的時候會返回 200,那么客戶端下一次請求則使用 HTTP/1.1 ;
- 2xx: 成功;
- 3xx: 重定向,如地址欄鍵入 http://www.google.com ,瀏覽器會重定向到 https://www.google.com ,該過程是一個自動的二次請求過程,就是通過返回的 301 (Moved Permanently 永久性遷移, 302 為臨時遷移,304 表示內(nèi)容沒有改變,F(xiàn)5 重新刷新該網(wǎng)頁)狀態(tài)碼來告訴客戶端重新請求;
- 4xx: 客戶端(瀏覽器、手機軟件)錯誤,如參數(shù)錯誤,服務(wù)器無法識別該請求,是可以修正的;
- 5xx: 服務(wù)器錯誤,如資源不足、資源找不到。
Header
作用:Header 描述了 HTTP 消息的元信息 (Meta Data),通俗地說就是描述數(shù)據(jù)的數(shù)據(jù),如:該消息有多長?是什么格式?數(shù)據(jù)有沒有壓縮?返回的數(shù)據(jù)是什么字符集等等。
Host
在前面的例子中,有一個 Host 的字段,它表示服務(wù)器主機地址,但是它不是用來尋址的,尋址的過程在發(fā)送請求之前就已經(jīng)做好了。
在發(fā)送請求前,瀏覽器會帶著域名「詢問」 DNS(Domain Name System 域名系統(tǒng)) 目標(biāo) IP 地址,然后 DNS 返回一個或多個 IP 地址,然后通過 IP 地址去尋址,然后發(fā)送報文給目標(biāo)服務(wù)器。
那么為什么在請求 Header 中為什么還要帶上 Host ?
是因為一個服務(wù)器主機下可能有多個虛擬主機或多個子服務(wù)器(多個網(wǎng)站)存在,也就是同樣一個 IP 地址下面會有多個服務(wù)器存在,由于它們對外的 IP 都是一樣的,瀏覽器根據(jù)這個 IP 去請求服務(wù)器,服務(wù)器會無法識別該次請求訪問具體哪個主機,最終得不到正確的響應(yīng),所以需要發(fā)送 Host 附加到 Header 到服務(wù)器。
服務(wù)器地址一般的形式是:域名 + TCP 端口。
Content-Type/Content-Length
描述 Body 的類型和長度。
- Content-Length:內(nèi)容的長度(字節(jié))
為什么會有 Content-Type 的存在?
是因為請求報文中,可能會攜帶二進(jìn)制非文本數(shù)據(jù),二進(jìn)制數(shù)據(jù)本身是不受限制的,它表示著各種各樣的字節(jié),那么如何表示內(nèi)容字節(jié)結(jié)束?此時 Content-Type 的作用就是表示規(guī)定一個長度,長度范圍內(nèi)讀取數(shù)據(jù),長度過后的數(shù)據(jù),直接扔棄。
- Content-Type:內(nèi)容的類型
text/html: html 文本,用于瀏覽器頁面響應(yīng)。
application/x-www-form-urlencoded: 普通表單,encode URL 格式,只作用于文本。
表單,可以簡單的理解為:一個要提交的表,是瀏覽器和服務(wù)器溝通的一個格式。通過表單,服務(wù)器會解析本次請求的 Body 內(nèi)容,找對應(yīng)參數(shù)。
multipart/form-data: 多部分形式,一般用于包含二進(jìn)制內(nèi)容的多項內(nèi)容。后面會跟 boundary=----WebKitFormBoundaryxxxxxx,它的作用是用來分界 Body 和 Header 以及 Body 的各個屬性。如修改人物信息的時候,通常會附帶普通的「名字信息」和「頭像圖片」,那么請求格式如下:
POST /users HTTP/1.1
Host: twitter.com
Content-Type: multipart/form-data boundary=----WebKitFormBoundary247HFSSj7fgwj01
Content-Length:2300
------WebKitFormBoundary247HFSSj7fgwj01 // 分界
Content-Disposition:form-data; name="user_name"http:// user_name 屬性
valentizx
------WebKitFormBoundary247HFSSj7fgwj01 // 分界
Content-Dispostion: form-data; name="avatar";filename="valentizx.jpg" // avatar 屬性
Content-Type: image/jpeg
SFH72jfoa6GSKHGS....
------WebKitFormBoundary247HFSSj7fgwj0-- // 分界
分界前面有 6 個 「-」,前兩個「-」表示一個新的屬性的開始,最后一個分界后面有兩個「-」表示結(jié)束。
application/json: json 形式,多用于 Web Api 的響應(yīng)或 PUT/POST 請求
image/jpeg、application/zip ...: 但文件,用于 Web Api 響應(yīng)或 POST/PUT 請求。
Chunked Transfer Encoding 分塊傳輸
當(dāng)一次請求的響應(yīng)數(shù)據(jù)內(nèi)容較大時,為不影響用戶體驗,服務(wù)器通常會返回一個 chunk 單位的數(shù)據(jù)給客戶端,但是服務(wù)器不會告訴 Header 每一個 chunk 具體多長,也就是 Body 長度無法確定,此時 Content-Type 無法使用。于是,新的 Body 格式出現(xiàn):
<length1>
<data1>
<length2>
<data2>
0
// ?此處有換行位?
明確每一小段(chunk)的長度放到 Header 中,先傳輸 data1,當(dāng) data2 準(zhǔn)備就緒的時候傳輸 data2,直到傳輸 0 + 換行 表示內(nèi)容結(jié)束。
Location
重定向的目標(biāo) URL,一次請求返回 301 的時候,瀏覽器會進(jìn)行重定向到 Location 字段后的地址再進(jìn)行一次請求。
User-Agent
用戶代理,就是指客戶端(Client),網(wǎng)頁會根據(jù)不同的設(shè)備進(jìn)行適配,標(biāo)識憑借就是 User-Agent。
Range/Accept-Range
指定 Body 的內(nèi)容范圍,當(dāng)目標(biāo)服務(wù)器支持分段取內(nèi)容的時候,該字段發(fā)揮作用,其最主要的兩個應(yīng)用點就是:斷點續(xù)傳和分段下載。
Cookie/Set-Cookie
發(fā)送 Cookie,設(shè)置 Cookie
Authorization
授權(quán)信息
部分其他 Header
Accept: 客戶端能接受的數(shù)據(jù)類型。如 text/html
Accept-Charset: 客戶端度接受的字符集。如 utf-8
Accept-Encoding: 客戶端接受的壓縮編碼類型。如 gzip
Content-Encoding: 壓縮類型。如 gzip
Cache
Cache 和 Buffer
- Cache:緩存,表示一塊內(nèi)容可能多次使用,所以這部分內(nèi)容暫時放在緩存區(qū)域中,當(dāng)不用的時候會被回收掉,面向速度;
- Buffer: 緩沖,工作過程中,上游生產(chǎn)快下游不能及時消費,或者下游暫時無消費,時間段過后會「猛」消費,則需要緩沖機制,提前生產(chǎn)一點存起來供下游使用,面向工作流;
Cache-Control
no-cache、no-store、max-age:
- no-cache: 服務(wù)器告訴 Client 端,該內(nèi)容可以緩存,但是再次請求的時候服務(wù)器需要知道緩存的內(nèi)容是否失效;
- no-store: 不許緩存;
- max-age: 在失效日期內(nèi),Client 端隨意訪問;
Last-Modified
If-Modified-Since: 緩存界面最后的修改時間,請求過程中,服務(wù)器會對比緩存的最后修改時間和真實文件的最后修改時間,如果一致,說明文件沒有改動過,返回 304,否則返回 200 和新的內(nèi)容。
Etag
If-None-Match: 相當(dāng)于 Hash,或者說相當(dāng)于一個指紋,Client 端也可憑借該字段與服務(wù)器「溝通」,對比這個標(biāo)簽,如果不是最新的,則請求最新的,返回 200 顯示新內(nèi)容,如果一致,則 返回 304。
Cache-Control
private 和 public,一次請求的實際過程可能極其復(fù)雜,通過各個節(jié)點,各個網(wǎng)關(guān),private 和 public 就是告訴路上經(jīng)過的這些中間節(jié)點是否需要幫助緩存信息。
? private 并不表示內(nèi)容的私密性,私密性是通過加密機制來實現(xiàn)的,它表示「個性化定制信息」。
REST
REST:對 HTTP 進(jìn)行一種限制,屬于一種架構(gòu)風(fēng)格。
- Server-Client architecture
- Statelessness
- Cacheability
- Layered system
- Code on demand
- Uniform interface
- Resource identification in requests
- Resource manipulation through representations
- Self-descriptive messages
- Hypermedia as the engine of application state (HATEOAS)
RESTful HTTP
規(guī)范 HTTP 的使用方式,正確的使用 HTTP。