【问题标题】:Upload binary data to AppEngine Blobstore via HTTP request通过 HTTP 请求将二进制数据上传到 AppEngine Blobstore
【发布时间】:2012-07-24 01:46:32
【问题描述】:

我试图找出从 JavaScript 发起的 HTTP 请求上传/下载二进制数据到 Google AppEngine 的 Blobstore 的最低数据开销方式。理想情况下,我想直接提交二进制数据,即未编码的 8 位值;也许在一个看起来像这样的 POST 请求中:

...
Content-Type: multipart/form-data; boundary=boundary;

--boundary
Content-Disposition: form-data; name="a"; filename="b"
Content-Type: application/octet-stream

@#^%(^Qtr...
--boundary--

这里,@#^%(^Qtr... 理想地表示任意 8 位二进制数据。

具体来说,我想了解以下内容:

  • 是否可以直接上传 8 位二进制数据,还是需要以某种方式对数据进行编码,例如 base-64 MIME 编码?
  • 如果我使用不同的编码,Blobstore 会将数据保存为内部的 8 位二进制文​​件还是编码格式? IE。 base-64 编码会增加 33% 的存储成本吗?
  • 同理:编码开销会增加传出带宽成本吗?
  • 有没有更好的方法来格式化 POST 请求,这样我就不需要想出一个不会出现在我的二进制数据中的boundary?例如。有没有办法指定 Content-Length 而不是边界?
  • 在检索数据的 GET 请求中,我是否可以简单地期望二进制数据以返回字符串结尾,或者服务器会以某种方式自动对数据进行编码?
  • 如果我需要使用某种编码,在支持的基本随机 8 位数据选项中,哪一种是最佳选择? (base-64、UTF-8 还是其他?)

【问题讨论】:

    标签: javascript google-app-engine upload binary blobstore


    【解决方案1】:

    即使我收到了Tumbleweed Badge 来回答这个问题,让我报告一下我的进展,以防有人关心:

    这个问题最终提出了 3 个独立的问题:

    1. 高效地将数据上传到 BlobStore
    2. 确保 BlobStore 以尽可能小的格式保存
    3. 找到可靠下载数据的方法

    让我们从 (3) 开始,因为这最终会带来最大的问题:

    到目前为止,我还没有找到通过 XHR 将真正的 8 位数据下载到浏览器的方法。使用诸如 application/octet-stream 之类的 mime 类型会导致只有 7 位可靠地到达客户端,除非将数据下载到文件中。我发现的最佳解决方案是对数据使用以下 mime 类型:

    text/plain; charset=ISO-8859-1
    

    我测试过的所有浏览器似乎都支持此功能:IE 8、Chrome 21、FF 12.0、Opera 11.61、Windows 下的 Safari 5.1.2 和 Android 2.3.3。

    这样,几乎可以传输任何 8 位值,但有以下限制/警告:

    • 字符 0x00 在 IE8 中被解释为输入字符串的结尾,因此必须避免。
    • 大多数浏览器将字符集 ISO-8859-1 解释为 Windows-1252,从而导致字符 0x80 到 0x9F 相应更改。但是,这可以修复,因为更改是明确的。 (见http://en.wikipedia.org/wiki/Windows-1252#Codepage_layout
    • 字符 0x81、0x8D、0x8F、0x90、0x9D 在 Windows-1252 字符集中保留,Opera 会为这些字符返回错误代码,因此也需要避免这些字符。

    总的来说,我们可以使用 256 个字符中的 250 个。有了数据所需的基础更改,这意味着传出数据开销低于 0.5%,我想我可以接受。

    那么,现在到问题(1)和(2):

    由于传入带宽是免费的,因此我决定降低解决问题 (1) 的优先级,以支持问题 (2) 和 (3)。事实证明,使用以下 POST 请求可以解决问题:

    ...
    Content-Type: multipart/form-data; boundary=-
    
    ---
    Content-Disposition: form-data; name="a"; filename="b"
    Content-Type: text/plain; charset=ISO-8859-1
    Content-Transfer-Encoding: base64
    
    abcd==
    -----
    

    这里,abcd== 是由上述 250 个允许字符组成的 base64-MIME 编码数据(请参阅http://en.wikipedia.org/wiki/Base64#Examples,GAE 使用 + 和 / 作为最后 2 个字符)。编码是必要的(如果我错了,请纠正我),因为使用字符串数据调用 XHR send() 函数将导致字符串的 UTF-8 编码,这会破坏服务器接收到的数据。不幸的是,并非所有浏览器都可以将 ArrayBuffers 和 Blobs 传递给 send() 函数,从而更优雅地规避这个问题。

    现在好消息:AppEngine BlobStore 会自动正确地解码这些数据,并在没有开销的情况下存储它!因此,使用 base64 编码只会导致客户端的数据上传速度变慢,但不会导致额外的托管成本(除非可能需要几个 CPU 周期进行解码)。

    除此之外:AppEngine 开发服务器将在管理控制台和检索到的 BlobInfo 记录中报告存储的 blob 的编码大小(即大 33%)。但是,生产服务器没有这个问题,并且报告了正确的 blob 大小。

    结论

    使用 Content-Transfer-Encoding base64 上传 Content-Type text/plain; charset=ISO-8859-1 的二进制数据,其中可能不包含字符 0x00、0x81、0x8D、0x8F、0x90 和 0x9D,从而为许多测试提供可靠的数据传输存储/传出带宽开销低于 0.5% 的浏览器。 base64 编码数据的上传开销为 33%,优于 UTF-8(对于随机 8 位数据)的预期 50%,但仍远非理想。

    我不知道的是:这是最佳解决方案,还是可以做得更好?有人愿意挑战吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-15
      • 2010-09-25
      • 1970-01-01
      • 1970-01-01
      • 2018-12-03
      • 1970-01-01
      • 2020-03-23
      • 1970-01-01
      相关资源
      最近更新 更多