nginx lua gzip解壓縮INFLATE: Data error, no input bytes報錯問題解決

nginx lua 對gzip請求數據包解壓失敗的問題

背景

我使用openresty+lua部署的nginx服務器,其中使用gzip針對數據包進行解壓縮處理,然後再對部分數據修改完畢後,使用gzip進行壓縮,然後再發送給接收端。
zlib參考如下
https://github.com/hamishforbes/lua-ffi-zlib

問題復現

在使用上述github的方法後,針對大部分請求都是能夠成功進行解壓與壓縮,但是又部分頁面一直會提示解壓失敗,錯誤log如下

INFLATE: Data error, no input bytes

解決思路

經過源碼分析,可以確認zlib解壓及壓縮的過程是ok的,經過debug發現,web的請求包是Transfer-Encoding: chunked的方式,該方式會把數據包切割成一個個chunked包然後進行發送。
問題就出現在chunked包上,針對大部分的請求包,每一個chunked包就是一個完整的gzip包(完整的意思是該包有gzip的開始和結束標誌位)。但是仍然有小部分數據是把一個完整的gzip包切割成了小塊數據包,導致針對這些小塊的數據包無法單獨進行解壓縮。
因此,需要對這些數據包進行整合拼接,拼接完整後,再進行解壓縮操作即可

解決方法

openresty中的api–ngx.arg

ngx.arg 在 body filter 階段用來讀取、更新應答數據。其中 ngx.arg[1]是待發送的 body,ngx.arg[2]
指示後續是否還有待發送數據

因此可以利用ngx.arg[2]來判斷是否是完整的數據包

local Content_Encoding = ngx.resp.get_headers()["Content-Encoding"]

if ngx.re.find(Content_Encoding, [=[gzip]=],"oij") then
	-- 此處爲了防止數據包不完整導致gzip解壓失敗
	if not ngx.ctx.ngx_all_content then
		ngx.ctx.ngx_all_content = ngx.arg[1]
	else
		ngx.ctx.ngx_all_content = ngx.ctx.ngx_all_content .. ngx.arg[1]
	end
    ngx.arg[1] = nil  --pass原有的數據
    if ngx.arg[2] then
    	 -- 當數據包標誌爲true時,證明一個完整的gzip包已經拼接完成,
    	 -- 此時就可以進行解壓縮操作
         html = zlib_uncompress(ngx.ctx.ngx_all_content) or ""
    end
end

發佈了107 篇原創文章 · 獲贊 98 · 訪問量 28萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章