【问题标题】:Referencing AWS S3 bucket name programmatically instead of hardcoded以编程方式而不是硬编码引用 AWS S3 存储桶名称
【发布时间】:2020-04-17 22:38:44
【问题描述】:

我正在使用 AWS Amplify 开发 iOS 应用程序。我通过 S3 添加了存储来托管一些资产,并尝试配置应用程序以下载它们。唯一的问题是我看到的每个示例都有存储桶名称和路径硬编码,但是因为我有多个环境并且有时会创建新环境并且每个存储桶都附加了环境名称,所以我不想重写存储桶每次都命名。

例如,如果我在我的测试环境中,存储桶名称可能是 assetsxxxxxx-test,但如果我切换到新环境,我可能会引用 assetsyyyyy-dev 假设。

问题是在 aswconfiguration.json 文件中引用了存储桶名称:

"S3TransferUtility": {
    "Default": {
        "Bucket": "assetsxxxxx-test",
        "Region": "us-east-2"
    }
}

所以我的问题是如何以编程方式引用该存储桶名称,以便在切换环境时重写该字段时,我不必更改代码。

谢谢

【问题讨论】:

    标签: amazon-web-services amazon-s3 aws-amplify aws-sdk-ios


    【解决方案1】:

    我不清楚您使用什么来构建您的 Amplify 资源(cloudformation、terraform、?console?等),然后创建您的“aswconfiguration.json 文件”。但听起来您需要传入一个非常可实现的动态变量。

    如果您使用代码管道、代码构建安排来部署您的资源和配置文件,您可以在代码构建阶段使用 bash 命令(sed 或 perl)来更改变量。或者自定义 lambda 来更新文件内容并复制到 S3,然后将动态变量传递给环境变量参数。

    通常,如果这是一个 cloudformation 模板,您可以使用伪参数引用 !Sub command,然后该参数将在早期声明并引用它所在的任何环境,例如

    “桶”:“assetsxxxxxx-${Environment}”

    【讨论】:

    • 谢谢!使用 Amplify CLI 配置放大资源,该 CLI 为每个资源生成自己的 cloudformation 模板。我对实际切换环境没有任何问题,因为 amplify 使它像调用“放大 env checkout {env name}”然后“放大拉取”一样简单,awsconfiguration.json 存储桶名称将自动更改为正确的存储桶。我的问题是如何在 swift 代码中引用该存储桶名称,而不是在传输实用程序要求存储桶名称时硬编码字符串?
    【解决方案2】:

    我也有同样的问题。我的解决方案类似但不完全相同。 首先,我创建了这样的 Codable 结构

    import Foundation
    
    struct AwsConfiguration: Codable {
        struct S3TransferUtility : Codable {
            private enum CodingKeys: String, CodingKey {
                case defaultConfig = "Default"
            }
    
            struct DefaultConfig : Codable {
                private enum CodingKeys: String, CodingKey {
                    case bucket = "Bucket"
                    case region = "Region"
                }
                var bucket: String
                var region: String
            }
    
            var defaultConfig: DefaultConfig
        }
    
        private enum CodingKeys: String, CodingKey {
            case s3TransferUtility = "S3TransferUtility"
        }
    
        var s3TransferUtility: S3TransferUtility
    }
    

    然后我定义了一个 DataHelper 类

    final class DataHelper {
        static func load<T: Decodable>(_ filename: String, as type: T.Type = T.self) -> T {
            let data: Data
    
            guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
                else {
                    fatalError("Couldn't find \(filename) in main bundle.")
            }
    
            do {
                data = try Data(contentsOf: file)
            } catch {
                fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
            }
    
            do {
                let decoder = JSONDecoder()
                return try decoder.decode(T.self, from: data)
            } catch {
                fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
            }
        }
    }
    

    然后将awsconfiguration.json 放入您的测试目标中。 然后你可以像这样写一个单元测试

        func testReadAWSConfiguration() throws {
            let config: AwsConfiguration = DataHelper.load("awsconfiguration.json")
    
            print ("************config bucket: \(config.s3TransferUtility.defaultConfig.bucket) " +
                "\n************config region: \(config.s3TransferUtility.defaultConfig.region)")
            XCTAssertNotEqual("", config.s3TransferUtility.defaultConfig.bucket)
            XCTAssertNotEqual("", config.s3TransferUtility.defaultConfig.region)
        }
    
    

    【讨论】:

      【解决方案3】:

      我解决了。对于其他想知道的人,我仍然不确定 AWS 开发工具包中是否内置了一个字段,但我决定将 awsconfiguration.json 文件直接解析为自定义结构:

      struct AWSConfigurationJSON: Codable{
          let S3TransferUtility: S3TransferUtility
      }
      
      struct S3TransferUtility: Codable{
          let Default: S3TransferUtilityDefault
      }
      
      struct S3TransferUtilityDefault: Codable{
          let Bucket: String
          let Region: String
      }
      

      然后我读取了文件并解析了 JSON。

      if let path = Bundle.main.path(forResource: "awsconfiguration", ofType: "json") {
                  do{
                      let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
                      let jsonResult = try JSONDecoder().decode(AWSConfigurationJSON.self, from: data)
                      print(jsonResult.S3TransferUtility.Default.Bucket)
                      bucketPath = jsonResult.S3TransferUtility.Default.Bucket
                  }catch let e{
                      print("error \(e)")
                      bucketPath = ""
      
                  }
              }else{
                  bucketPath = ""
      
              }
      

      【讨论】:

        【解决方案4】:

        您可以使用以下方式访问存储桶名称:

        if let s3TransferInfo = AWSInfo.default().defaultServiceInfo("S3TransferUtility") {
            self.bucket = s3TransferInfo.infoDictionary["Bucket"] as? String
        }
        

        所以你不需要滚动你自己的 JSON 解析配置

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-11-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-08-07
          • 2020-07-16
          相关资源
          最近更新 更多