我有一个go-gin应用程序,它允许在S3中上传和下载多种文件类型.

上传到S3之前的所有文件都使用AWS S3加密客户端、使用AES GCM和来自KMS的密钥进行加密.因此,就S3存储桶而言,一切都是二进制的.

我可以使用getObject的SDK命令将文件下载到服务器,对其进行解密,然后使用io.write(临时文件)将该文件提供给客户端进行下载.

这里的问题S3包含10 GB大小的文件,并且该服务器每天将被多个用户访问.正如我们所看到的,在具有16 GB内存的服务器上写入临时文件会很快耗尽内存,让我们也注意到运行这样的服务器的成本.

瓶颈是在提供服务之前需要对文件进行解密,在此用例中,S3签名URL就足够了,尽管解密不是由S3预签名URL提供的,除非其加密是由客户完成的,在我们的 case 中是由AWS处理加密,所以这个解决方案是不可行的.

有谁有任何技巧或可能的用例来克服这个问题,在这些用例中,我们可以使用go-gin/nginx将文件直接写入客户端.

用户当前对文件下载的处理

s3FileStream, _ := s3c.GetBucketItem(&utils.S3ObjectBucketInput{
    Bucket: "bucketName",
    Key:    "UserFileName"
})

fileBody, err := io.ReadAll(s3FileStream.Body)
if err != nil {
    panic(err.Error())
}

fileExtension := s3FileStream.Metadata["X-Amz-Meta-Type"]

err = ioutil.WriteFile("file" + *fileExtension, fileBody, 600) // temp file
if err != nil {
    panic(err.Error())
}
c.JSON(http.StatusCreated, string(fileBody))
c.Done()

}

推荐答案

一种 Select 是将对象作为响应体直接写入客户端:

s3FileStream, _ := s3c.GetBucketItem(&utils.S3ObjectBucketInput{
    Bucket: "bucketName",
    Key:    "UserFileName",
})
fileExtension := s3FileStream.Metadata["X-Amz-Meta-Type"]
c.DataFromReader(http.StatusCreated, 0, "application/data",
    s3FileStream.Body,
    map[string]string{"Content-Dispositon": "attachment; filename=" + "file" + *fileExtension})
c.Done()

Go相关问答推荐

如何将泛型函数作为参数传递给golang中的另一个函数?

如何在使用中介资源时处理函数中的`defer`

按键值排序字符串- Golang

如何在jsonrpc服务器的服务器端捕获错误?

如何为循环扫描的bufio scanner 设置超时?

如何获取集群外go Kubernetes客户端的当前命名空间?

如何在golang中使用viper获取对象的配置数组?

我应该先解锁然后再广播吗?

GORM中是否可能自动迁移具有循环关系的表?

尽管存在 WaitGroup,Goroutines 似乎被打断了

如何使用 go-git 将特定分支推送到远程

如何从 Go 中的 `HijackedResponse` 中删除 Cursor Position ANSI 转义码?

如何确定作为函数参数传递的指针是否正在被修改或副本是否正在被修改?

Go http.FileServer 给出意外的 404 错误

assert: mock: I don't know what to return because the method call was unexpected 在 Go 中编写单元测试时出错

函数超时和 goroutine 泄漏

在 Raspberry Pi4 上下载 Go Mod

如何在测试中使用自定义标志(使用`testify/suite`)

如何使用 context.WithCancel 启动和停止每个会话的心跳?

在 etcd 键值存储中禁用历史记录