【问题标题】:Retrieve bucket's objects without knowing bucket's region with AWS S3 REST API使用 AWS S3 REST API 在不知道存储桶区域的情况下检索存储桶的对象
【发布时间】:2015-01-21 09:31:09
【问题描述】:

我正在尝试使用 AWS S3 REST API 检索存储桶的对象(我没有使用 SDK),但不幸的是我遇到了以下问题:当我调用API。

这就是我的工作:

  • 我向“https:// [bucketname] .s3.amazonaws.com/”构建了一个请求
  • 我使用设置为“us-west-1”的默认区域对请求进行签名(使用 AWS4 签名过程)
  • 但想象一下,我尝试 GET 的存储桶设置为区域“us-west-2”,AWS 给我一个错误

因此这是我的问题:

有没有办法在不知道其区域的情况下获取存储桶的对象列表?或者有什么简单的方法来获取桶的区域?

INFO:我读过有两种调用存储桶的样式,“路径样式”和“虚拟托管样式”,但是每当我将请求发送到“https://s3.amazonaws.com/ [bucketname]”时,它都会给出我重定向永久错误...

【问题讨论】:

    标签: rest amazon-web-services amazon-s3


    【解决方案1】:

    AWS V4 身份验证要求您知道存储桶的区域,以便您可以正确签署请求。否则:

    HTTP/1.1 400 Bad Request
    
    <?xml version="1.0" encoding="UTF-8"?>
    <Error>
      <Code>AuthorizationHeaderMalformed</Code>
      <Message>The authorization header is malformed; the region 'us-east-1' is wrong; expecting 'us-west-2'</Message>
      <Region>us-west-2</Region>
      <RequestId>xxxx</RequestId>
      <HostId>xxxx</HostId>
    </Error>
    

    V2 签名不是特定于区域的,因此以前有一种简单的方法可以使用 V2 请求来了解存储桶的区域:

    http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGETlocation.html

    但是,V4 似乎有一个 catch-22,因为您必须先知道存储桶的区域,然后才能进行调用以发现存储桶的区域。

    那么,第一个解决方案是捕获错误响应中返回的&lt;Region&gt;,并使用该区域对存储桶的未来请求进行签名。显然,您希望缓存这些信息,因为不这样做会降低性能并增加成本。

    或者,有一种方法可以仅使用以下 URL 格式向美国标准区域 (us-east-1) 询问任何区域中任何存储桶的位置:

    https://s3.amazonaws.com/bucket-name?location
    

    使用 us-east-1 区域签署此请求,无论存储桶在哪里,您都会收到响应。请注意,如果存储桶位于 us-east-1(美国标准)中,则 LocationConstraint 将返回为空。

    <?xml version="1.0" encoding="UTF-8"?>
    <LocationConstraint xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
      us-west-2
    </LocationConstraint>
    

    您不能使用此 URL 构造来实际列出其他区域中的存储桶对象,因为 https://s3.amazonaws.com/ 始终将您的请求路由到 US-Standard (us-east-1),但您可以使用它来发现任何存储桶的区域,因为 US-Standard 提供了这些信息。


    更新/附加

    在某些时候,S3 似乎添加了一个新的响应标头x-amx-bucket-region:,它似乎是对 REST API 的无证补充,似乎添加到许多 S3 错误响应中,尤其是 403 错误。

    如果您收到错误响应,这似乎是一种有用的自我纠正机制。

    此外,上述关于向美国标准区域询问任何存储桶位置的信息仍然准确,如果将相同的请求发送到任何区域 S3 REST 端点,而不仅仅是美国标准,因为所有区域知道所有其他存储桶的位置:例如https://s3-us-west-2.amazonaws.com/bucket-name?location 会询问 US-West-2(俄勒冈),它也有相同的可用信息,用于全球任何存储桶。在某些情况下可能需要询问您最近的区域。

    【讨论】:

    【解决方案2】:

    在 Ruby 中,你可以在获取资源时这样传递区域:

    s3 = Aws::S3::Resource.new(region: 'us-west-2')
    

    【讨论】:

      【解决方案3】:

      您可以从异常中获取区域 -> 其他详细信息

                  AmazonS3 client = AmazonS3ClientBuilder.standard()
                  .withCredentials(new AWSStaticCredentialsProvider(credentials)).withRegion(Regions.US_EAST_1).build();
                  Regions bucketRegion = Regions.US_EAST_1;    
                  try {
                      client.getBucketLocation(bucket.getName());
                  } catch (AmazonS3Exception e) {
                      bucketRegion = Regions.fromName(e.getAdditionalDetails().get("Region"));
                  }
      

      这不是最好的方法,但现在别无选择。

      【讨论】:

        【解决方案4】:

        如果您的请求只是指向错误的区域,S3 将以 临时 重定向响应。由于您提到它正在回复 permanent 重定向,这表明请求不正确。 S3 通常会在响应正文中回复一条有用的消息,以帮助找出问题所在。您需要阅读响应的正文以更正请求。

        【讨论】:

        • 感谢您的回答:)
        【解决方案5】:

        在@patrice-gagnon 响应之后,我在 AWS 实例化中注入了区域配置,它对我有用。

        顺便说一句,我在 NestJS 中使用 Typescript

        const s3 = new AWS.S3({ region: 'eu-west-3' });
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-06-03
          • 1970-01-01
          • 2021-08-02
          • 2016-03-02
          • 2015-12-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多