尝试上传到 AWS S3 时无法从任何提供商加载凭据

Could not load credentials from any providers when attempting upload to AWS S3

我似乎无法获得正确的授权。

我已经创建了在 AWS S3 上使用的存储桶。

我已经在两个 AWS 上创建了访问密钥和秘密,并按照指定将它们作为 Heroku 上的环境变量输入 here

我已验证访问密钥在配置日志中可见。

我错过了什么?

我目前正在本地主机上尝试此操作,因此我手动更新配置的情况,但后来我希望服务器代码在 Heroku 上 运行。

客户端:

   async upload(adId: string, file: File) {
        const url = this.baseUrl + `api/image/${adId}`
        const fileName = this.createUniqueFileName(adId, file)
        const data = { fileName: fileName, fileType: file.type }
        const response = await axios.post(url, data, { headers: { 'Content-Type': 'application/json' } }) // Fetch a signed AWS S3 url from ad-keeper
        const formData = new FormData()
        formData.append(fileName, file)
        const awsS3Response = await axios.put(response.data.signedUrl, formData, { headers: { 'Content-Type': 'multipart/form-data' } }) // Upload file to AWS S3 bucket
        return awsS3Response.status === 200
    }

服务器端:

   app.post('/api/image/:adId', (request, response) => {
        const s3 = new aws.S3()
        if (request.headers.host.includes('localhost')) {
            aws.config.update({ region: localHostAwsConfig.region, accessKeyId: localHostAwsConfig.accessKeyId, secretAccessKey: localHostAwsConfig.secretAccessKey })
        }
        const fileName = request.body.fileName
        const fileType = request.body.fileType
        const bucketName = process.env.AWS_S3_BUCKET_NAME || "localhost-bucket"
        const params = {
            Bucket: bucketName,
            Key: fileName,
            Expires: 60,
            ContentType: fileType,
            ACL: 'public-read'
        }
        console.log(aws.config)
        s3.getSignedUrl('putObject', params, (error, data) => {
            if (error) {
                console.log(error)
                return response.status(500).end() // Server call ends up here
            }
            const imageUrl = `https://${bucketName}.s3.amazonaws.com/${fileName}`
            adSource.setImageUrl(request.params.adId, imageUrl)
            return response.json({ signedRequest: data, imageUrl: imageUrl })
        });
    });

打印配置:

Config {
  credentials: Credentials {
    expired: false,
    expireTime: null,
    refreshCallbacks: [],
    accessKeyId: '<ACCESS_KEY>',
    sessionToken: undefined
  },
  credentialProvider: CredentialProviderChain {
    providers: [
      [Function],
      [Function],
      [Function],
      [Function],
      [Function],
      [Function]
    ],
    resolveCallbacks: []
  },
  region: 'eu-north-1',
  logger: null,
  apiVersions: {},
  apiVersion: null,
  endpoint: undefined,
  httpOptions: { timeout: 120000 },
  maxRetries: undefined,
  maxRedirects: 10,
  paramValidation: true,
  sslEnabled: true,
  s3ForcePathStyle: false,
  s3BucketEndpoint: false,
  s3DisableBodySigning: true,
  computeChecksums: true,
  convertResponseTypes: true,
  correctClockSkew: false,
  customUserAgent: null,
  dynamoDbCrc32: true,
  systemClockOffset: 0,
  signatureVersion: null,
  signatureCache: true,
  retryDelayOptions: {},
  useAccelerateEndpoint: false,
  clientSideMonitoring: false,
  endpointDiscoveryEnabled: false,
  endpointCacheSize: 1000,
  hostPrefixEnabled: true
}

打印错误:

Error: connect ETIMEDOUT 169.254.169.254:80
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1054:14) {
  message: 'Missing credentials in config',
  errno: 'ETIMEDOUT',
  code: 'CredentialsError',
  syscall: 'connect',
  address: '169.254.169.254',
  port: 80,
  time: 2019-05-15T15:11:01.789Z,
  originalError: {
    message: 'Could not load credentials from any providers',
    errno: 'ETIMEDOUT',
    code: 'CredentialsError',
    syscall: 'connect',
    address: '169.254.169.254',
    port: 80,
    time: 2019-05-15T15:11:01.789Z,
    originalError: {
      errno: 'ETIMEDOUT',
      code: 'ETIMEDOUT',
      syscall: 'connect',
      address: '169.254.169.254',
      port: 80,
      message: 'connect ETIMEDOUT 169.254.169.254:80'
    }
  }
}

您应该在 执行 s3 = new aws.S3() 之前使用凭据 调用 aws.config.update()。否则配置更新将不会绑定到 S3 对象,它将使用默认凭证链。

还要确保访问密钥和密钥是正确的,但我认为这不是这里的问题。