Go 項(xiàng)目實(shí)戰(zhàn):實(shí)現(xiàn)一個(gè)提供壓縮文件下載功能的 http server
最近遇到了一個(gè)下載靜態(tài)html報(bào)表的需求,需要以提供壓縮包的形式完成下載功能,實(shí)現(xiàn)的過(guò)程中發(fā)現(xiàn)相關(guān)文檔非常雜,故總結(jié)一下自己的實(shí)現(xiàn)。
開(kāi)發(fā)環(huán)境:
系統(tǒng)環(huán)境:MacOS + Chrome 框架:beego 壓縮功能:tar + gzip 目標(biāo)壓縮文件:自帶數(shù)據(jù)和全部包的靜態(tài)html文件
首先先提一下http server文件下載的實(shí)現(xiàn),其實(shí)就是在后端返回前端的數(shù)據(jù)包中,將數(shù)據(jù)頭設(shè)置為下載文件的格式,這樣前端收到返回的響應(yīng)時(shí),會(huì)直接觸發(fā)下載功能(就像時(shí)平時(shí)我們?cè)赾hrome中點(diǎn)擊下載那樣)
數(shù)據(jù)頭設(shè)置格式如下:
func?(c?*Controller)Download()?{
????//...文件信息的產(chǎn)生邏輯
????//
????//rw為responseWriter
????rw?:=?c.Ctx.ResponseWriter
????//規(guī)定下載后的文件名
????rw.Header().Set("Content-Disposition",?"attachment;?filename="+"(文件名字)")
????rw.Header().Set("Content-Description",?"File?Transfer")
????//標(biāo)明傳輸文件類(lèi)型
????//如果是其他類(lèi)型,請(qǐng)參照:https://www.runoob.com/http/http-content-type.html
????rw.Header().Set("Content-Type",?"application/octet-stream")
????rw.Header().Set("Content-Transfer-Encoding",?"binary")
????rw.Header().Set("Expires",?"0")
????rw.Header().Set("Cache-Control",?"must-revalidate")
????rw.Header().Set("Pragma",?"public")
????rw.WriteHeader(http.StatusOK)
????//文件的傳輸是用byte slice類(lèi)型,本例子中:b是一個(gè)bytes.Buffer,則需調(diào)用b.Bytes()
????http.ServeContent(rw,?c.Ctx.Request,?"(文件名字)",?time.Now(),?bytes.NewReader(b.Bytes()))
}
這樣,beego后端就會(huì)將在頭部標(biāo)記為下載文件的數(shù)據(jù)包發(fā)送給前端,前端收到后會(huì)自動(dòng)啟動(dòng)下載功能。
然而這只是最后一步的情況,如何將我們的文件先進(jìn)行壓縮再發(fā)送給前端提供下載呢?
如果需要下載的不只一個(gè)文件,需要用tar打包,再用gzip進(jìn)行壓縮,實(shí)現(xiàn)如下:
//最內(nèi)層用bytes.Buffer來(lái)進(jìn)行文件的存儲(chǔ)
var?b?bytes.Buffer
//嵌套tar包的writter和gzip包的writer
gw?:=?gzip.NewWriter(&b)
tw?:=?tar.NewWriter(gw)
dataFile?:=?//...文件的產(chǎn)生邏輯,dataFile為File類(lèi)型
info,?_?:=?dataFile.Stat()
header,?_?:=?tar.FileInfoHeader(info,?"")
//下載后當(dāng)前文件的路徑設(shè)置
header.Name?=?"report"?+?"/"?+?header.Name
err?:=?tw.WriteHeader(header)
if?err?!=?nil?{
??utils.LogErrorln(err.Error())
??return
}
_,?err?=?io.Copy(tw,?dataFile)
if?err?!=?nil?{
??utils.LogErrorln(err.Error())
}
//...可以繼續(xù)添加文件
//tar?writer?和?gzip?writer的關(guān)閉順序一定不能反
tw.Close()
gw.Close()
最后和中間步驟完成了,我們只剩File文件的產(chǎn)生邏輯了,由于是靜態(tài)html文件,我們需要把所有html引用的依賴(lài)包全部完整的寫(xiě)入到生成的文件中的
原文作者:Hoofffman
原文鏈接:https://segmentfault.com/a/1190000038867527
推薦閱讀
