JavaScriptを有効にしてください

【Go】GinでAWS S3からダウンロードしたデータを圧縮して返却する

 ·  ☕ 2 分で読めます · 👀... ページ閲覧数

概要

APIにファイルダウンロードを機能追加する際、Go言語のginを使うとどんな感じにできるのか気になったのでやってみた。その時のメモ。
ファイルは事前にAWS S3にアップロードされている想定。

バージョン

  • Go: v1.13.4
  • gin: v1.7.1
  • aws-sdk-go: v1.38.36

S3からファイルをダウンロードする

初めにAWS S3からファイルをダウンロードして内容を標準出力することをやってみる。

ファイルのダウンロードはローカルにファイルを落としてくる方式とStreamとして扱う方法とあるみたい。
ローカルにダウンロードする必要はないのでGetObjectを利用する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
    "bytes"
    "fmt"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3"
)

func main() {
    sess := session.Must(session.NewSession(&aws.Config{
        Region: aws.String("ap-northeast-1"),
    }))
    s3handler := s3.New(sess)

    obj, _ := s3handler.GetObject(&s3.GetObjectInput{
        Bucket: aws.String("2021-test-bucket"),     // ダウンロードしたいS3オブジェクトがアップロードされているS3バケット
        Key:    aws.String("sample.txt"),           // キー (ファイル)名
    })

    body := obj.Body
    defer obj.Body.Close()

    buf := new(bytes.Buffer)
    buf.ReadFrom(body)
    fmt.Print(buf.String())
}

実行するとダウンロードしたファイルの内容が表示された。

1
2
$ go run main.go
# this is sample text

ginを使ってレスポンスに圧縮したファイルを返す

stackoverflowにファイルの圧縮について質問しているQAがあった(stackoverflow
これと、【Golang】S3上のデータをメモリ上に乗せずにストリーミングしてレスポンスへ流す【AWS】が非常に参考になった。

レスポンスに設定したzipへ追加したfileのWriterにS3からダウンロードしたobjectのReaderを流している。
S3のデータをローカルにダウンロードしたり、zipファイルを作成することなくレスポンスを返すことができる。すごい。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package main

import (
    "archive/zip"
    "io"
    "log"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3"
    "github.com/gin-gonic/gin"
)

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

        sess := session.Must(session.NewSession(&aws.Config{
            Region: aws.String("ap-northeast-1"),
        }))
        s3handler := s3.New(sess)

        obj, err := s3handler.GetObject(&s3.GetObjectInput{
            Bucket: aws.String("2021-test-bucket"),
            Key:    aws.String("sample.txt"),
        })

        if err != nil {
            log.Print(err)
        }

        body := obj.Body
        defer obj.Body.Close()

        c.Stream(func(w io.Writer) bool {
            ar := zip.NewWriter(w)
            defer ar.Close()

            c.Writer.Header().Set("Content-Disposition", "attachment; filename=download.zip")

            f, _ := ar.Create("sample.txt")
            io.Copy(f, body)

            return false
        })
    })

    engine.Run(":3000")
}

共有

BAMBi
著者
BAMBi
サーバサイド~インフラがメインでフロントも好きです。趣味はアニメ鑑賞、ゲーム、つまみ細工です。