背景
gzip解壓縮在http請(qǐng)求里面經(jīng)常聽(tīng)到從來(lái)沒(méi)有真正的處理過(guò)浑娜,今天終于遇到個(gè)問(wèn)題瓮钥。先描述一下問(wèn)題,hiproxy是一個(gè)代理服務(wù)器湖苞。在給hiproxy寫(xiě)一個(gè)插件的時(shí)候拯欧,需要拿到所有請(qǐng)求的數(shù)據(jù),包括http協(xié)議字段和數(shù)據(jù)部分财骨。重點(diǎn)在數(shù)據(jù)部分镐作,hiproxy作為一個(gè)代理,其實(shí)并不關(guān)心請(qǐng)求是否是gzip解壓縮的隆箩。因?yàn)榻鈮菏菫g覽器來(lái)做该贾,壓縮是服務(wù)器來(lái)做。但是我的數(shù)據(jù)是在代理的節(jié)點(diǎn)去拿到數(shù)據(jù)捌臊。這時(shí)候悲劇就來(lái)了杨蛋,怎么去解壓數(shù)據(jù)。
http chunk
http chunk見(jiàn)的比較多。bigpipe應(yīng)該就算http chunk傳輸數(shù)據(jù)的一種逞力。http請(qǐng)求不停的輸出chunk數(shù)據(jù)曙寡,直到結(jié)束。那第一個(gè)問(wèn)題來(lái)了寇荧。所有的數(shù)據(jù)是先拆chunk后gzip举庶,還是先gzip后拆chunk的呢?我猜是第一種揩抡,google了一下户侥,說(shuō)是兩種方式都支持!麻痹捅膘,我相信了添祸。
查了node的zlib包,發(fā)現(xiàn)解壓有兩種方式寻仗。第一種stream流管道解壓。另外一種就是直接解壓buffer凡壤。然后我就在response的data事件回調(diào)中開(kāi)始操作了署尤。拿到chunk一看是buffer,判斷一下encodeing亚侠,直接調(diào)用zlib.upzip解壓了曹体,不幸的是拋異常了:Z_DATA_ERROR。這不應(yīng)該呀硝烂,那換種姿勢(shì)吧箕别,buffer轉(zhuǎn)stream用管道的方式去解壓。麻痹滞谢,還是不行串稀。這時(shí)候開(kāi)始懷疑人生了。
開(kāi)始google, 都是一些gz文件解壓狮杨,或者response用管道解壓返回gz數(shù)據(jù)母截。終于我開(kāi)始懷疑第一個(gè)問(wèn)題了,到底是先gzip還是先拆chunk橄教。最后換種姿勢(shì)吧清寇,data事件里面緩存chunk,chunk用Buffer.concat拼接起來(lái)护蝶。end事件里面再判斷encoding华烟,選擇zlib.gunzip解壓。窩草持灰,成功了盔夜。。。
到底發(fā)生了什么事情
查看了一下http協(xié)議比吭,寫(xiě)的明明白白绽族,先gzip再拆分。想一下衩藤,先拆chunk再gzip好像也沒(méi)啥問(wèn)題呀吧慢。那為什么這么搞呢?猜測(cè)一下赏表,首先检诗,先拆包再gzip的話(huà),勢(shì)必?cái)?shù)據(jù)量會(huì)變大瓢剿。gzip也是有數(shù)據(jù)寫(xiě)入的呀逢慌!窩草,又想到一個(gè)問(wèn)題间狂。不是說(shuō)瀏覽器解析html是回一個(gè)chunk數(shù)據(jù)就開(kāi)始解析了嗎攻泼?我開(kāi)始懷疑這個(gè)說(shuō)法了。如果沒(méi)有g(shù)zip那我能理解鉴象,你瀏覽器可以提前渲染忙菠,但是gzip了你都沒(méi)辦法解壓,渲染個(gè)屁胺谋住牛欢!