如何使用 Gin 在 HTTP 服务器中动态生成 zip / 7z 存档?

How to generate zip / 7z archive on the fly in a HTTP server using Gin?

我使用 Gin 创建一个 HTTP 服务器,我想为用户提供一个动态生成的 zip 存档。

理论上我可以先在文件系统上生成一个 zip 文件然后提供它。但这确实是一种糟糕的方式(在开始下载之前等待 5 分钟)。我想立即开始将其提供给用户并在生成内容时推送内容。

我找到了 DataFromReader (example),但在归档完成之前不知道 ContentLength。

func DownloadEndpoint(c *gin.Context) {
    ...
    c.DataFromReader(
        http.StatusOK,
        ContentLength,
        ContentType,
        Body,
        map[string]string{
            "Content-Disposition": "attachment; filename=\"archive.zip\""),
        },
    )
}

我该怎么做?

使用 stream method and archive/zip 您可以即时创建 zip 并将它们流式传输到服务器。

package main

import (
    "os"

    "archive/zip"

    "github.com/gin-gonic/gin"
)

func main() {

    r := gin.Default()
    r.GET("/", func(c *gin.Context) {

        c.Writer.Header().Set("Content-type", "application/octet-stream")
        c.Stream(func(w io.Writer) bool {

            // Create a zip archive.
            ar := zip.NewWriter(w)

            file1, _ := os.Open("filename1")
            file2, _ := os.Open("filename2")
            c.Writer.Header().Set("Content-Disposition", "attachment; filename='filename.zip'")

            f1, _ := ar.Create("filename1")
            io.Copy(f1, file1)
            f2, _ := ar.Create("filename2")
            io.Copy(f2, file2)

            ar.Close()

            return false
        })
    })
    r.Run()
}

直接使用ResponseWriter

package main

import (
    "io"
    "os"

    "archive/zip"

    "github.com/gin-gonic/gin"
)


func main() {

    r := gin.Default()
    r.GET("/", func(c *gin.Context) {
        c.Writer.Header().Set("Content-type", "application/octet-stream")
        c.Writer.Header().Set("Content-Disposition", "attachment; filename='filename.zip'")
        ar :=  zip.NewWriter(c.Writer)
        file1, _ := os.Open("filename1")
        file2, _ := os.Open("filename2")
        f1, _ := ar.Create("filename1")
        io.Copy(f1, file1)
        f2, _ := ar.Create("filename1")
        io.Copy(f1, file2)
        ar.Close()
    })
    r.Run()
}