HTTP概述
HTTP協(xié)議是什么
HTTP協(xié)議(HyperText Transfer Protocol),又稱(chēng)超文本傳輸協(xié)議,是網(wǎng)絡(luò)模型中應(yīng)用層的一個(gè)協(xié)議,通常被用來(lái)在一個(gè)服務(wù)端程序和客戶(hù)端程序間傳輸HTTP報(bào)文(下文會(huì)提到),以達(dá)到傳輸HTML文件、圖片、視頻的效果。
HTTP使用TCP作為它的支撐運(yùn)輸協(xié)議,這句話(huà)的意思是,HTTP協(xié)議本身并沒(méi)有傳輸?shù)牟糠郑鼉H僅是把需要傳輸?shù)膬?nèi)容封裝為HTTP數(shù)據(jù)報(bào),然后交給TCP協(xié)議去傳輸,由于TCP協(xié)議是一個(gè)可靠的協(xié)議,這也就意味著在一般情況下,一個(gè)客戶(hù)端進(jìn)程發(fā)出的HTTP請(qǐng)求總能完整的到達(dá)服務(wù)器,反過(guò)來(lái),我們也可以認(rèn)為在一般情況下服務(wù)器返回的HTTP報(bào)文也總能完整的到達(dá)發(fā)出響應(yīng)請(qǐng)求的客戶(hù)端。
HTTP是一個(gè)無(wú)狀態(tài)協(xié)議
HTTP是一個(gè)無(wú)狀態(tài)協(xié)議,這句話(huà)的意思是說(shuō)服務(wù)端程序在向客戶(hù)端程序發(fā)送文件時(shí)并不會(huì)存儲(chǔ)任何客戶(hù)端的狀態(tài)信息,這是有悖于我們的常識(shí)的,因?yàn)楝F(xiàn)在我們?cè)跒g覽網(wǎng)頁(yè)時(shí)大部分的信息都與賬戶(hù)信息有關(guān)(比如登陸電商網(wǎng)站去查看自己的購(gòu)物車(chē)數(shù)據(jù)),但是在互聯(lián)網(wǎng)最初的時(shí)候大部分網(wǎng)頁(yè)都是靜態(tài)的,并不需要做任何與用戶(hù)信息相關(guān)的交互,但是隨著互聯(lián)網(wǎng)的發(fā)展,這種與用戶(hù)信息之間交互的需求越來(lái)越多,開(kāi)發(fā)人員就想到了在HTTP報(bào)文中添加一個(gè)叫做cookie的東西來(lái)解決這一問(wèn)題,但是我們?nèi)匀徽J(rèn)為HTTP協(xié)議是一個(gè)無(wú)狀態(tài)協(xié)議,因?yàn)橥ㄟ^(guò)cookie來(lái)返回相應(yīng)的數(shù)據(jù)是后端程序的任務(wù),與HTTP協(xié)議本身無(wú)關(guān)。
HTTP的非持續(xù)連接和持續(xù)連接
非持續(xù)連接
非持續(xù)性鏈接即每一個(gè)連接只傳輸一個(gè)文件,比如我們?cè)L問(wèn)百度首頁(yè)時(shí)除了要獲取百度首頁(yè)的html文件,還要下載百度首頁(yè)的logo,如果采用非持續(xù)連接,將會(huì)產(chǎn)生兩個(gè)TCP傳輸通道,用來(lái)分別傳輸html文檔和圖片。
我們知道TCP在連接時(shí)有一個(gè)三次握手和四次揮手的過(guò)程,這個(gè)過(guò)程會(huì)消耗一定的時(shí)間,在默認(rèn)情況下,一個(gè)瀏覽器能夠打開(kāi)5~10個(gè)并行的TCP連接,當(dāng)請(qǐng)求的文件數(shù)大于該數(shù)目的時(shí)候,頻繁的握手與揮手會(huì)導(dǎo)致時(shí)間上的損耗。同時(shí)頻繁的創(chuàng)建與銷(xiāo)毀TCP連接也會(huì)帶來(lái)一些服務(wù)器性能上的損耗。
持續(xù)連接
持續(xù)連接即盡可能的復(fù)用客戶(hù)端與服務(wù)端的TCP連接,意思就是在傳輸完當(dāng)前的文件后不立即關(guān)閉該TCP連接,而是等待一段時(shí)間(可自由設(shè)置),如果在等待的時(shí)間內(nèi)再次收到客戶(hù)端的請(qǐng)求,則繼續(xù)使用該TCP連接來(lái)進(jìn)行傳輸。這樣一來(lái)就解決了非持續(xù)連接帶來(lái)的問(wèn)題,但同時(shí)如果等待時(shí)間設(shè)置得不合理也會(huì)帶來(lái)許多問(wèn)題,應(yīng)合理的設(shè)置等待的時(shí)間。
HTTP報(bào)文
請(qǐng)求報(bào)文
一個(gè)典型的HTTP請(qǐng)求報(bào)文結(jié)構(gòu)如下圖所示

請(qǐng)求報(bào)文是由一行請(qǐng)求行和若干行首部行(headers)以及實(shí)體體(entity body,也有別的叫法叫請(qǐng)求體)組成,其中只有請(qǐng)求行是必須的,其他兩個(gè)在某些情況下并不一定會(huì)存在。
在linux下我們可以使用crul命令來(lái)查看HTTP的請(qǐng)求報(bào)文和響應(yīng)報(bào)文
我們使用
curl -v http://www.baidu.com/命令來(lái)查看當(dāng)訪(fǎng)問(wèn)百度時(shí)的HTTP請(qǐng)求報(bào)文,部分返回結(jié)果如下所示
請(qǐng)求行
請(qǐng)求行有三個(gè)字段,分別是方法字段、URL字段和HTTP版本字段
方法字段
HTTP的方法包括GET、POST、HEAD、PUT和DELETE五種。
絕大多數(shù)的HTTP請(qǐng)求都使用的是GET方法,當(dāng)我們?cè)跒g覽器中輸入一個(gè)網(wǎng)址得到相應(yīng)的網(wǎng)頁(yè)時(shí),也是使用的GET方法。
POST方法用來(lái)向服務(wù)器提交一些信息,比如說(shuō)登陸時(shí)的用戶(hù)名和密碼,這些信息被保存在上面提到的實(shí)體體中,然后被傳輸?shù)椒?wù)器。
HEAD方法與GET方法類(lèi)似,它們的區(qū)別僅在于HEAD方法不會(huì)返回GET方法請(qǐng)求的對(duì)象(比如HTML文件),僅僅返回請(qǐng)求行和首部行。
PUT方法用來(lái)向服務(wù)器端上傳文件。
DELETE用來(lái)刪除服務(wù)器上的文件。
URL字段
即我們請(qǐng)求的文件在服務(wù)器中的位置,因?yàn)槲覀冞@里訪(fǎng)問(wèn)的是百度的首頁(yè),默認(rèn)的就是根路徑,所以這里的URL字段為“/”,如果我們使用curl -v http://www.baidu.com/index.php,URL字段的值就會(huì)是"/index.php"
HTTP版本
傳輸使用的HTTP協(xié)議的版本,在這個(gè)示例中我們使用的是HTTP1.1
首部行
首部行中存儲(chǔ)著一些信息,多條首部行之間用回車(chē)符和換行符隔開(kāi),常見(jiàn)的如Host,用來(lái)表示請(qǐng)求訪(fǎng)問(wèn)的主機(jī)名、User-Agent,用來(lái)表示發(fā)出客戶(hù)端請(qǐng)求的瀏覽器版本,由于我這里使用的是curl命令所以顯示的是curl
實(shí)體體
在上文中已經(jīng)提到過(guò),存儲(chǔ)請(qǐng)求的信息,但并不是每一個(gè)HTTP請(qǐng)求報(bào)文都有實(shí)體體
響應(yīng)報(bào)文
一個(gè)典型的HTTP響應(yīng)報(bào)文結(jié)構(gòu)如下圖所示

可以看出響應(yīng)報(bào)文的結(jié)構(gòu)與請(qǐng)求報(bào)文結(jié)構(gòu)很相似,僅僅是把請(qǐng)求行更改為了狀態(tài)行
同樣我們使用
curl -v http://www.baidu.com命令查看該響應(yīng)報(bào)頭
狀態(tài)行
版本
與請(qǐng)求報(bào)文相同,代表HTTP的版本
狀態(tài)碼與短語(yǔ)
狀態(tài)碼與短語(yǔ)是一一對(duì)應(yīng)的,它們結(jié)合起來(lái)共同反應(yīng)了請(qǐng)求的結(jié)果,下面是一些常見(jiàn)的狀態(tài)碼與短語(yǔ)以及它們所代表的含義
- 200 OK:請(qǐng)求成功,信息在返回的響應(yīng)報(bào)文中
- 301 Moved Permanently:請(qǐng)求的對(duì)象已經(jīng)被永久轉(zhuǎn)移了,但是并沒(méi)有刪除,該對(duì)象現(xiàn)在在服務(wù)器中的路徑會(huì)被放在響應(yīng)報(bào)文的Location:xxxxxxx首部行中,以便于客戶(hù)端再次請(qǐng)求
- 400 Bad Request:一個(gè)通用的差錯(cuò)代碼,指該請(qǐng)求服務(wù)器不能理解
- 404 Not Found:請(qǐng)求的內(nèi)容在服務(wù)器上不存在
- 505 HTTP Version Not Support:服務(wù)器不支持請(qǐng)求所用的HTTP協(xié)議版本
首部行
響應(yīng)報(bào)文的首部行和請(qǐng)求報(bào)文的首部行作用基本一致,所以這里僅僅介紹幾個(gè)常見(jiàn)的響應(yīng)報(bào)文首部行的含義。
- Connection:close/Keep-Alive 分別對(duì)應(yīng)上面說(shuō)到的該HTTP使用非持續(xù)連接還是持續(xù)連接
- Date 服務(wù)器發(fā)送該響應(yīng)報(bào)文的時(shí)間
- Content-Length 響應(yīng)報(bào)文中實(shí)體體的長(zhǎng)度,單位是byte
- Content-Type 響應(yīng)報(bào)文返回的對(duì)象類(lèi)型,可以看到這里返回的是一個(gè)html文檔或者普通文檔類(lèi)型
- Last-Modified 該文件在服務(wù)器上最后被修改的時(shí)間,這一條我們最后在說(shuō)代理服務(wù)器的時(shí)候會(huì)再次說(shuō)到
- Server 響應(yīng)的服務(wù)器的名稱(chēng)以及版本
代理服務(wù)器相關(guān)
如果所有的網(wǎng)絡(luò)請(qǐng)求都直接向其初始服務(wù)器發(fā)送的話(huà),會(huì)給初始服務(wù)器帶來(lái)嚴(yán)重的負(fù)擔(dān),此時(shí)我們需要在客戶(hù)端和服務(wù)端之間架設(shè)代理服務(wù)器來(lái)解決這一問(wèn)題(如下圖所示)。

它的工作原理是這樣的,客戶(hù)端發(fā)送的請(qǐng)求首先發(fā)送到代理服務(wù)器,如果代理服務(wù)器中存在客戶(hù)端想要的內(nèi)容,那么代理服務(wù)器就可以把該內(nèi)容直接返回,不需要向原始服務(wù)器發(fā)送請(qǐng)求,從而減少了初始服務(wù)器的負(fù)擔(dān)。以上的內(nèi)容可能比較抽象,下邊我們通過(guò)一個(gè)例子來(lái)分析。
假如我是第一次訪(fǎng)問(wèn)百度的首頁(yè),且代理服務(wù)器中沒(méi)有保存相關(guān)的對(duì)象,那么整個(gè)流程的順序是這樣的
- 客戶(hù)端向代理服務(wù)器發(fā)送請(qǐng)求表示自己要請(qǐng)求百度的主頁(yè)
- 代理服務(wù)器先檢查本地是否有百度的主頁(yè),檢查后發(fā)現(xiàn)本地并沒(méi)有,于是代理服務(wù)器向初始服務(wù)器發(fā)送請(qǐng)求向初始服務(wù)器索要相關(guān)的對(duì)象
- 初始服務(wù)器接受到請(qǐng)求把請(qǐng)求的對(duì)象返回給代理服務(wù)器
- 代理服務(wù)器接收到初始服務(wù)器返回的對(duì)象,在本地保存一份副本之后再將該對(duì)象返回給客戶(hù)端
- 客戶(hù)端收到代理服務(wù)器返回的數(shù)據(jù),在瀏覽器上顯示相應(yīng)的界面
從此之后我再訪(fǎng)問(wèn)百度主頁(yè),整個(gè)流程就簡(jiǎn)單了很多,如下所示
- 客戶(hù)端向代理服務(wù)器發(fā)送請(qǐng)求表示自己要請(qǐng)求百度的主頁(yè)
- 代理服務(wù)器先檢查本地是否有百度的主頁(yè),檢查后發(fā)現(xiàn)本地有百度首頁(yè)的文件,將該對(duì)象返回給客戶(hù)端
- 客戶(hù)端收到代理服務(wù)器返回的數(shù)據(jù),在瀏覽器上顯示相應(yīng)的界面
但是這樣就導(dǎo)致了一個(gè)問(wèn)題,就是如果服務(wù)器上的文件在代理服務(wù)器保存之后進(jìn)行了更改怎么辦,這時(shí)就需要用到我們上面說(shuō)到的Last-Modified首部行,當(dāng)代理服務(wù)器接受到請(qǐng)求時(shí),它向初始服務(wù)器發(fā)送一個(gè)請(qǐng)求去對(duì)比本地文件的Last-Modified與服務(wù)器上的Last-Modified是否一致,如果一致就直接將本地的對(duì)象返回,如果不一致就再次從初始服務(wù)器下載一份覆蓋掉本地對(duì)象,再將該對(duì)象返回給客戶(hù)端。