为了账号安全,请及时绑定邮箱和手机立即绑定

使用 golang 的 http.ResponseWriter 进行 AWS S3 大文件反向代理

使用 golang 的 http.ResponseWriter 进行 AWS S3 大文件反向代理

Go
吃鸡游戏 2021-12-07 18:56:49
我有一个名为的请求处理程序Download,我想从 Amazon S3 访问一个大文件并将其推送到用户的浏览器。我的目标是:在授予用户访问文件的权限之前记录一些请求信息不要将文件过多地缓冲到内存中。文件可能会变得太大。这是我迄今为止探索的内容:func Download(w http.ResponseWriter, r *http.Request) {    sess := session.New(&aws.Config{        Region:             aws.String("eu-west-1"),        Endpoint:           aws.String("s3-eu-west-1.amazonaws.com"),        S3ForcePathStyle:   aws.Bool(true),        Credentials:        cred,    })    downloader := s3manager.NewDownloader(sess)    // I can't write directly into the ResponseWriter. It doesn't implement WriteAt.     // Besides, it doesn't seem like the right thing to do.    _, err := downloader.Download(w, &s3.GetObjectInput{        Bucket: aws.String(BUCKET),        Key: aws.String(filename),    })    if err != nil {        log.Error(4, err.Error())        return    }}我想知道是否没有更好的方法(考虑到我正在努力实现的目标)。欢迎任何建议。先感谢您 :-)
查看完整描述

2 回答

?
白板的微信

TA贡献1883条经验 获得超3个赞

如果文件可能很大,您不希望它通过您自己的服务器。最好的方法(在我看来)是让用户直接从 S3 下载它。


您可以通过生成预先签名的 url来做到这一点:


func Download(w http.ResponseWriter, r *http.Request) {


    ...


    sess := session.New(&aws.Config{

        Region:             aws.String("eu-west-1"),

        Endpoint:           aws.String("s3-eu-west-1.amazonaws.com"),

        S3ForcePathStyle:   aws.Bool(true),

        Credentials:        cred,

    })


    s3svc := s3.New(sess)

    req, _ := s3svc.GetObjectRequest(&s3.GetObjectInput{

        Bucket: aws.String(BUCKET),

        Key: aws.String(filename),

    })


    url, err := req.Presign(5 * time.Minute)

    if err != nil {

        //handle error

    }


    http.Redirect(w, r, url, http.StatusTemporaryRedirect)

}

预签名 url 仅在有限的时间内有效(在本例中为 5 分钟,根据您的需要进行调整)并将用户直接带到 S3。再也不用担心下载了!


查看完整回答
反对 回复 2021-12-07
?
慕娘9325324

TA贡献1783条经验 获得超4个赞

如果您确实想通过您的服务流式传输文件(而不是按照已接受的答案中的建议直接下载)-


import (

    ...


    "github.com/aws/aws-sdk-go/aws"

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

)


func StreamDownloadHandler(w http.ResponseWriter, r *http.Request) {


    sess, awsSessErr := session.NewSession(&aws.Config{

        Region:      aws.String("eu-west-1"),

        Credentials: credentials.NewStaticCredentials("my-aws-id", "my-aws-secret", ""),

    })

    if awsSessErr != nil {

        http.Error(w, fmt.Sprintf("Error creating aws session %s", awsSessErr.Error()), http.StatusInternalServerError)

        return

    }


    result, err := s3.New(sess).GetObject(&s3.GetObjectInput{

        Bucket: aws.String("my-bucket"),

        Key:    aws.String("my-file-id"),

    })

    if err != nil {

        http.Error(w, fmt.Sprintf("Error getting file from s3 %s", err.Error()), http.StatusInternalServerError)

        return

    }


    w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", "my-file.csv"))

    w.Header().Set("Cache-Control", "no-store")


    bytesWritten, copyErr := io.Copy(w, result.Body)

    if copyErr != nil {

        http.Error(w, fmt.Sprintf("Error copying file to the http response %s", copyErr.Error()), http.StatusInternalServerError)

        return

    }

    log.Printf("Download of \"%s\" complete. Wrote %s bytes", "my-file.csv", strconv.FormatInt(bytesWritten, 10))

}


查看完整回答
反对 回复 2021-12-07
  • 2 回答
  • 0 关注
  • 258 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信