如何在Go中从AWS S3下载对象到内存并通过请求发送它?

huangapple go评论103阅读模式
英文:

How to download object from AWS S3 into memory and send it via request in Go?

问题

有人可以帮我解决我在尝试从S3下载文件时遇到的错误吗?

所以我想通过Go Gin创建存储服务API,并且我想要一个路由,它接受S3对象键以下载对象,然后将此对象发送回客户端。

cfg,_ := config.LoadDefaultConfig(context.TODO())

// 创建 Amazon S3 服务客户端
s3Client := s3.NewFromConfig(cfg)
downloader := manager.NewDownloader(s3Client)
router.POST("/download-s3", func(ctx *gin.Context) {
    var data map[string]string

    if err := ctx.ShouldBindJSON(&data); err != nil {
        log.Println("Error: bind error")
        ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    log.Println("Body Request data (fileKey): ", data["fileKey"])

    fileKey := data["fileKey"]

    // 缓冲区读取
    buf := make([]byte, 100)
    // 使用 aws.WriteAtBuffer 进行包装
    w := manager.NewWriteAtBuffer(buf)
    // 将文件下载到内存中
    numBytesDownloaded, err := downloader.Download(ctx, w, &s3.GetObjectInput{
        Bucket: aws.String(bucketName),
        Key:    aws.String(fileKey),
    })
    if err != nil {
        log.Println("Error: download error")
        ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    ctx.JSON(http.StatusAccepted,
        gin.H{
            "message":            fmt.Sprintf("'%s' downloaded!", "test.jpg"),
            "numBytesDownloaded": numBytesDownloaded,
        },
    )

    ctx.Data(http.StatusOK, "application/octet-stream", w.Bytes())

})

上述代码给我返回了以下错误:
operation error S3: GetObject, https response error StatusCode: 403, RequestID: 8KHYW3RCS2ZA7D95, HostID: kOLo+gY/dTzrROVswsB1bxinlN8w+XDL0LNMySUWJNHUPMBVk4ItdfP+mQ2xuo8ehaSnX/FaI4I=, api error AccessDenied: Access Denied

请求体的格式如下:

{
    "filekey": "https://xxx-xxx.s3.ap-southeast-1.amazonaws.com/agencies/photo/06%3A03%3A2023_17%3A42%3A42_gggi_db_er.png"
}

我在.env文件中存储了所有这些AWS_S3_BUCKET_NAME、AWS_REGION、AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY,而且我认为我已经正确设置了它们,因为我有另一个将文件上传到S3的路由(这个路由工作得很好)。

英文:

Can someone please help me solve this error I got while trying to download a file from S3.

So I want to create storage service api via Go Gin, and I want a route where it take S3 object key to download the object then send this object back to client.

cfg,_ := config.LoadDefaultConfig(context.TODO())

// Create an Amazon S3 service client
s3Client := s3.NewFromConfig(cfg)
downloader := manager.NewDownloader(s3Client)
	router.POST("/download-s3", func(ctx *gin.Context) {
		var data map[string]string

		if err := ctx.ShouldBindJSON(&data); err != nil {
			log.Println("Error: bind error")
			ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		log.Println("Body Request data (fileKey): ", data["fileKey"])

		fileKey := data["fileKey"]

		/// Buffer read
		buf := make([]byte, 100)
		// wrap with aws.WriteAtBuffer
		w := manager.NewWriteAtBuffer(buf)
		// download file into the memory
		numBytesDownloaded, err := downloader.Download(ctx, w, &s3.GetObjectInput{
			Bucket: aws.String(bucketName),
			Key:    aws.String(fileKey),
		})
		if err != nil {
			log.Println("Error: download error")
			ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		ctx.JSON(http.StatusAccepted,
			gin.H{
				"message":            fmt.Sprintf("'%s' downloaded!", "test.jpg"),
				"numBytesDownloaded": numBytesDownloaded,
			},
		)

		ctx.Data(http.StatusOK, "application/octet-stream", w.Bytes())

	})

This above code gave me this error of :
operation error S3: GetObject, https response error StatusCode: 403, RequestID: 8KHYW3RCS2ZA7D95, HostID: kOLo+gY/dTzrROVswsB1bxinlN8w+XDL0LNMySUWJNHUPMBVk4ItdfP+mQ2xuo8ehaSnX/FaI4I=, api error AccessDenied: Access Denied

Request body is something like this:

{
    "filekey": "https://xxx-xxx.s3.ap-southeast-1.amazonaws.com/agencies/photo/06%3A03%3A2023_17%3A42%3A42_gggi_db_er.png"
}

I got all these AWS_S3_BUCKET_NAME, AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY stored in .env file, plus I think I set them right since I got another route to upload file to S3 (which work just fine).

答案1

得分: 2

你的fileKey是一个像这样的URL:

"https://xxx-xxx.s3.ap-southeast-1.amazonaws.com/agencies/photo/06%3A03%3A2023_17%3A42%3A42_gggi_db_er.png"

这只能在HTTP客户端(如Web浏览器或curl)中使用。

具体来说,它不是一个有效的S3对象键。在使用GetObject或类似的S3 API时,它需要是一个有效的键,例如agencies/photo/xyz.png,而且不应该进行URL编码。

英文:

Your fileKey is a URL like this:

"https://xxx-xxx.s3.ap-southeast-1.amazonaws.com/agencies/photo/06%3A03%3A2023_17%3A42%3A42_gggi_db_er.png"

That is only usable from an HTTP client such as a web browser or curl.

Specifically, it is not a valid S3 object key. When using GetObject or similar S3 APIs, it needs to be a valid key such as agencies/photo/xyz.png and should not be URL-encoded.

huangapple
  • 本文由 发表于 2023年3月7日 00:16:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/75653230.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定