尽管我因这个问题收到了Tumbleweed 徽章,但还是让我报告一下我的进度,以防有人在乎:
这个问题原来提出了 3 个独立的问题:
- 高效地将数据上传到 BlobStore
- 确保 BlobStore 以尽可能小的格式保存它
- 寻找可靠下载数据的方法
让我们从 (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 位值,但有以下限制/警告:
总的来说,我们可以使用 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-Encodingbase64
上传 Content-Type 的二进制数据text/plain; charset=ISO-8859-1
,其中可能不包含字符 0x00、0x81、0x8D、0x8F、0x90 和 0x9D,这会导致许多经过测试的浏览器的可靠数据传输具有存储/传出带宽开销不到半个百分点。base64 编码数据的上传开销为 33%,好于 UTF-8(对于随机 8 位数据)的预期 50%,但仍远非理想。
我不知道的是:这是最佳解决方案,还是可以做得更好?有人愿意挑战吗?