实现与 akka-http 兼容的基本 S3 API

Implementing basic S3 compatible API with akka-http

我正在尝试使用 akka-http.
实现与基本 S3 兼容 API 的文件存储 ыукмшсу 我使用 s3 java sdk 来测试我的服务 API 并发现了 putObject(...) 方法的问题。我无法在 akka-http 后端正确使用文件。为了测试目的,我写了简单的路线:

def putFile(bucket: String, file: String) = put{
      extractRequestEntity{ ent =>
      val finishedWriting = ent.dataBytes.runWith(FileIO.toPath(new File(s"/tmp/${file}").toPath))
      onComplete(finishedWriting) { ioResult =>
        complete("Finished writing data: " + ioResult)
      }
    }
  }

它保存了文件,但文件总是损坏。查看文件内部,我发现了如下几行:

"20000;chunk-signature=73c6b865ab5899b5b7596b8c11113a8df439489da42ddb5b8d0c861a0472f8a1".

当我尝试使用任何其他 rest 客户端 PUT 文件时,它工作正常。 我知道 S3 使用 "Expect: 100-continue" header 并且他可能会导致问题。 我真的不知道该如何处理。任何帮助表示赞赏。

这并没有完全损坏。您的服务没有考虑 S3 支持使用 Content-Encoding: aws-chunkedx-amz-content-sha256: STREAMING-AWS4-HMAC-SHA256-PAYLOAD.

在线发送上传的四种方法之一

它是一种 non-standards-based 流式传输 object 的机制,包括看起来完全像这样的块:

string(IntHexBase(chunk-size)) + ";chunk-signature=" + signature + \r\n + chunk-data + \r\n

...其中 IntHexBase() 是将整数格式化为十六进制数的函数的伪代码。

chunk-based algorithmTransfer-Encoding: chunked 相似,但不兼容,因为它在流中嵌入了校验和。

他们为什么要编一个新的HTTP传输编码?它在客户端可能很有用,因为它消除了 "read your payload twice or buffer [the entire object payload] in memory [concurrently]" 的需要——如果您要在上传开始之前计算 x-amz-content-sha256 哈希值,那么其中一个或另一个是必需的,因为您否则必须,因为完整性检查需要它。

我不太熟悉 Java SDK 的内部结构,但是这种类型的上传 可能 通过使用 .withInputStream() 触发,或者它可能也是文件或超过一定大小的文件的标准行为。

如果您在请求 headers 中看到 x-amz-content-sha256: STREAMING-AWS4-HMAC-SHA256-PAYLOAD,您的最低解决方法是抛出 HTTP 错误,因为您似乎没有在 API 中实现它,但这会很可能仅用于防止存储通过此方法上传的 objects。这还不是自动发生的事实表明您根本没有实现 x-amz-content-sha256 处理,因此您没有进行需要进行的 server-side 负载完整性检查。

为了完全兼容,您需要实现 S3 支持的算法,并且假定 SDK 可用,除非 SDK 特别支持禁用该算法的机制——这似乎不太可能,因为它服务于有用的目的,特别是(看起来)对于长度已知但不可搜索的流。


¹ 四分之一 -- 其他三个是标准 PUT、web-based html 形式 POST ,以及推荐用于大文件和大于 5 GB 的文件强制使用的多部分 API。