【问题标题】:Download a file from S3 using full URI using AWS SDK for Go使用适用于 Go 的 AWS 开发工具包使用完整 URI 从 S3 下载文件
【发布时间】:2018-09-06 11:44:38
【问题描述】:

我看到的使用适用于 Go 的 AWS 开发工具包从 S3 下载文件的示例采用以下形式:

downloader := s3manager.NewDownloader(session, /* other args */)

s3object := &s3.GetObjectInput{
    Bucket: aws.String(myBucket),
    Key: aws.String(myKey),
}

bytesDownloaded, err := downloader.Download(myFile, s3object)

即使用bucket和key来指定文件。但是,如果我已经在 S3 上拥有文件的完整 URI 怎么办?例如:

https://s3.us-west-2.amazonaws.com/myBucket/myKey

有没有办法使用SDK直接使用URL指定要下载的文件?

不,存储桶公开。在 SDK 中,我还设置了访问密钥和密钥(从示例代码中省略)。

最后,如果根本无法通过 SDK 完成我所要求的事情,那么这是一个可以接受(尽管不是理想)的答案。

【问题讨论】:

  • 存储桶是公开的吗? http.Get,无需 SDK。只要确保你看到的是森林。
  • 不,存储桶不是公开的。 (我已更新问题以明确说明这一点。)

标签: go amazon-s3 aws-sdk


【解决方案1】:

没有办法做你想做的事。获取私有对象的唯一方法是:

  1. 使用bucket和key下载文件
  2. 生成预签名 URL 并在该 URL 上执行 hhtp.Get(要生成预签名 URL,您需要存储桶和密钥)

如果您真的想使用 URL,我建议您围绕 s3.GetObjectInput 创建一个包装器,该包装器接受 URL 作为参数,对其进行解析,然后创建 s3.GetObjectInput 对象。

另外,我不知道您是否可以这样做,这取决于您的用例,但如果您将 URL 存储在某处并且这就是您想要使用它们的原因,您可以考虑使用长过期时间,然后当您想要获取对象时,您可以使用该 URL。

【讨论】:

  • 预签名 url 的最大生命周期为 7 天,因此稍后存储和检索它们不是最好的办法
【解决方案2】:

您可以解析 URL 以获取存储桶和密钥:

package main

import (
    "fmt"
    "log"
    "net/url"
    "strings"
)

func main() {
    u, err := url.Parse("https://s3.us-west-2.amazonaws.com/myBucket/myKey/morekey")
    if err != nil {
        log.Fatal(err)
    }

    path := strings.SplitN(u.Path, "/", 3)
    bucket := path[1]
    key := path[2]
    fmt.Println(bucket)
    fmt.Println(key)
}

可运行:https://play.golang.org/p/G3Mxmm4f4qM

【讨论】:

  • 是的,我知道我可以解析它。我特意问了有没有办法直接使用SDK。
  • 使用路径包来处理路径。例如,它将正确处理双斜杠。
  • @Peter 路径包与适用于 Go 的 AWS 开发工具包有什么关系?
  • @PaulJ.Lucas,什么都没有。它与 URL 解析有关。除非 URL 被规范化(例如,不包含双斜杠),否则 strings.Split* 函数不适用。
【解决方案3】:

为此创建了新的 S3URLtoURI 解析器。

func S3URLtoURI(s3Url string) (map[string]string, error) {
    m := make(map[string]string)
    u, err := url.Parse(s3Url)
    if err != nil {
        return m, err
    }

    if u.Scheme == "s3" {
        //s3: //bucket/key
        m["bucket"] = u.Host
        m["key"] = strings.TrimLeft(u.Path, "/")
    } else if u.Scheme == "https" {
        host := strings.SplitN(u.Host, ".", 2)
        if host[0] == "s3" {
            // No bucket name in the host;
            path := strings.SplitN(u.Path, "/", 3)
            m["bucket"] = path[1]
            m["key"] = path[2]
        } else { //bucket name in host
            m["bucket"] = host[0]
            m["key"] = strings.TrimLeft(u.Path, "/")
        }

    }
    return m, err
}

可运行:https://play.golang.org/p/vkPJ7E4Fyno

【讨论】:

    【解决方案4】:

    在这里,您首先需要对您尝试从 S3 下载的对象启用公共访问权限。您可以通过以下任一方法实现此目的。

    • 使对象公开可读。但请记住,无论谁获得了访问权 资源 url 可以从 S3 下载您的对象。
    • 通过存储桶策略授予对 S3 存储桶的匿名访问权限。 Refer here 使用策略样本了解此方法。记得验证 当你走这条路时你会暴露什么。
    • 使用PreSignedUrl允许限时下载对象 方式。这是我希望从上述方法中得到的。

    现在最后一步是使用 go 的 http client 调用您的预签名 url 并下载所需的对象。

    【讨论】:

    • 不,该对象不能公开读取。 (我已经更新了我的问题。)该对象只能由所有者访问,所以我认为您的任何建议都不会奏效。
    猜你喜欢
    • 1970-01-01
    • 2012-05-16
    • 2021-04-11
    • 1970-01-01
    • 2021-12-09
    • 2020-08-05
    • 1970-01-01
    • 2021-09-04
    • 2020-06-05
    相关资源
    最近更新 更多