由于http協(xié)議的簡(jiǎn)單性以及業(yè)務(wù)的需要,我們不可避免地需要自己去實(shí)現(xiàn)一些走http協(xié)議的server。
當(dāng)我們的短連接http服務(wù)器(如驗(yàn)證碼服務(wù)器)是客戶端是瀏覽器(ie、firefox、chrome)的時(shí)候,有一個(gè)問(wèn)題需要特別注意,我稱之為短連接http服務(wù)器陷阱。首先,先來(lái)看下面一系列同一個(gè)請(qǐng)求,但是不同抓包工具抓取的內(nèi)容的截圖:
圖1.使用httpwatch抓包獲取的內(nèi)容
圖2.使用sniffer抓包獲取的內(nèi)容
其中,兩者是同一個(gè)請(qǐng)求,從sniffer抓包內(nèi)容看、瀏覽器和server已經(jīng)完成了交互過(guò)程。但是瀏覽器(包括ie、firefox、chrome)的Result卻是ERROR_INTERNET_CONNECTION_RESET,這是為什么呢?
通過(guò)走讀server代碼,發(fā)現(xiàn)server做了這樣一個(gè)邏輯,在有請(qǐng)求過(guò)來(lái)的時(shí)候只讀取了100個(gè)字節(jié),因?yàn)?/span>server認(rèn)為這100個(gè)字節(jié)足夠判斷客戶端的請(qǐng)求行為(GET /HTTP/1.0 少于100個(gè)字節(jié)),而其它請(qǐng)求信息(包括cookie等等)是無(wú)用的,然后返回response信息,然后關(guān)閉連接。流程如下:
1)讀取100個(gè)字節(jié) => 2)返回response信息 => 3)關(guān)閉socket
當(dāng)客戶端請(qǐng)求的量不大的時(shí)候(內(nèi)網(wǎng)開(kāi)發(fā)機(jī)并發(fā)請(qǐng)求量<100)、很容易出現(xiàn)上文所述http服務(wù)器陷阱的問(wèn)題。當(dāng)客戶端請(qǐng)求的量很大的時(shí)候,出現(xiàn)上述問(wèn)題的幾率倒不大,但是偶爾也會(huì)出現(xiàn)。分析原因如下:
當(dāng)并發(fā)量很少的時(shí)候,server讀取了100個(gè)字節(jié)并返回response后,馬上關(guān)閉連接。由于并發(fā)量少,server處理速度很快,這樣很快就會(huì)關(guān)閉了連接。但是,此時(shí)客戶端(瀏覽器)也許還有一些數(shù)據(jù)(例如cookie信息等)并沒(méi)有真正發(fā)送到server的內(nèi)核緩沖區(qū)。于是,瀏覽器繼續(xù)把剩余的數(shù)據(jù)試圖發(fā)送到server,但是,此時(shí)發(fā)現(xiàn)server已經(jīng)關(guān)閉了連接,就會(huì)引發(fā)ERROR_INTERNET_CONNECTION_RESET錯(cuò)誤。雖然用sniffer抓包發(fā)現(xiàn)實(shí)際上整個(gè)交互過(guò)程已經(jīng)完成,但是瀏覽器缺認(rèn)為這是一個(gè)致命的錯(cuò)誤,獲取到的返回?cái)?shù)據(jù)并沒(méi)有正確的顯示在瀏覽器上。
當(dāng)并發(fā)量很大的時(shí)候,雖然server只讀取了100個(gè)字節(jié),但是由于服務(wù)器的處理能力有限,從讀取了100字節(jié)到關(guān)閉連接的過(guò)程有一定的時(shí)間差。客戶端可以在這個(gè)時(shí)間差的時(shí)間內(nèi)把剩余的數(shù)據(jù)發(fā)送到了server內(nèi)核緩沖區(qū)(雖然應(yīng)用程序沒(méi)有讀取這部分?jǐn)?shù)據(jù))。因此,出現(xiàn)ERROR_INTERNET_CONNECTION_RESET錯(cuò)誤的概率就會(huì)變小。
總結(jié),在實(shí)現(xiàn)短連接的http服務(wù)器(尤其是提供給瀏覽器使用的服務(wù)器)時(shí),盡量把http header數(shù)據(jù)包讀取完整,不要因?yàn)橹恍枰恍〔糠?/span>header信息就能處理請(qǐng)求而不讀取其它的頭部信息,以此來(lái)加快處理速度或者節(jié)省空間。這往往適得其反,可能會(huì)引起一些列不可預(yù)料的問(wèn)題。
由此,引發(fā)另一個(gè)思考,既然不可避免的需要讀取完整的http header數(shù)據(jù)包,那么,瀏覽器請(qǐng)求的時(shí)候,應(yīng)該盡量保持http header不要過(guò)于龐大,既是為了減緩server的壓力也是為了加快server的處理速度。而減少http header長(zhǎng)度的最好方法就是減少cookie的內(nèi)容。