通过HTTP请求将二进制数据上载到AppEngine Blobstore

时间:2012-07-25 15:13:00

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

我正在尝试找出从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位二进制吗?即base-64编码会使我的存储成本增加33%吗?
  • 沿着同样的路线:编码开销会增加传出带宽成本吗?
  • 是否有更好的格式化POST请求的方法,因此我不需要提出未出现在我的二进制数据中的boundary?例如。有没有办法指定内容长度而不是边界?
  • 在检索数据的GET请求中,我可以简单地期望在返回字符串中结束二进制数据,或者服务器是否会以某种方式自动编码数据?
  • 如果我需要使用一些编码,哪一个是基本随机8位数据支持的选项中的最佳选择? (base-64,UTF-8,其他什么?)

1 个答案:

答案 0 :(得分:1)

即使我收到了Tumbleweed Badge这个问题,但是如果有人关心我的话,请让我报告我的进展:

这个问题最终引发了3个独立问题:

  1. 有效地将数据上传到BlobStore
  2. 确保BlobStore以尽可能小的格式保存它
  3. 找到可靠下载数据的方法
  4. 让我们从(3)开始,因为这最终会带来最大的问题:

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

    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==是base64-MIME编码的数据,包含上述250个允许的字符(请参阅http://en.wikipedia.org/wiki/Base64#Examples,GAE使用+和/作为最后2个字符)。编码是必要的(如果我错了,请纠正我),因为使用String数据调用XHR send()函数将导致字符串的UTF-8编码,这会破坏服务器接收的数据。不幸的是,在所有浏览器中都没有将ArrayBuffers和Blob传递给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预期的50%(对于随机8位数据),但仍远远不够理想。

    我不知道的是:这是最佳解决方案,还是可以做得更好?任何人都可以接受挑战吗?