4

由于 Safari 和 AppEngine 的限制,我和我的团队对我们出色的动画应用无法在 Safari 上运行感到不满。我们希望你们中的一个可以帮助我们找到解决它的“魔法咒语”。

这可能是一个非常容易解决的问题,但两天后我们只遇到了砖墙,因为这是一个不常见(尽管非常有用)的场景,几乎没有记录。

让我解释一下问题的细节。

我们的应用程序需要将画布数据保存到 blobstore(用户为其动画绘制的图像)。通常,您可以通过 ajax 动态发布 Web 表单来实现此目的,其中包含图像数据的二进制字段。一种方法是使用 ArrayBuffer 和 BlobBuilder。这适用于 Chrome:

dataURItoBlob = function(dataURI, callback) {
  var ab, bb, byteString, i, ia, mimeString, _ref;
  if (!(typeof ArrayBuffer != "undefined" && ArrayBuffer !== null)) {
    return null;
  }
  byteString = atob(dataURI.split(',')[1]);
  mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
  ab = new ArrayBuffer(byteString.length);
  ia = new Uint8Array(ab);
  for (i = 0, _ref = byteString.length; (0 <= _ref ? i < _ref : i > _ref); (0 <= _ref ? i += 1 : i -= 1)) {
    ia[i] = byteString.charCodeAt(i);
  }
  bb = window.BlobBuilder ? new BlobBuilder() : window.WebKitBlobBuilder ? new WebKitBlobBuilder() : window.MozBlobBuilder ? new MozBlobBuilder() : void 0;
  if (bb != null) {
    bb.append(ab);
    return bb.getBlob(mimeString);
  } else {
    return null;
  }
};
postCanvasToBlobstore = function(url, name, canvas) {
        blob = dataURItoBlob(canvas.toDataURL());
        formData = new FormData();
        formData.append("file", blob);
        xhr = new XMLHttpRequest();
        xhr.open("POST", url);
        return xhr.send(formData);
}

保存二进制表单数据的另一种方法是使用 xhr.sendAsBinary()。这适用于火狐:

postCanvasToBlobstore = function(url, name, canvas) {
  type='image/png'
  var arr, boundary, data, j, xhr;
  data = canvas.toDataURL(type);
  data = data.replace('data:' + type + ';base64,', '');
  xhr = new XMLHttpRequest();
  xhr.open('POST', url, true);
  boundary = 'imaboundary';
  xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
    arr = ['--' + boundary, 'Content-Disposition: form-data; name="' + name + '"; filename="' + name + '"', 'Content-Type: ' + type, '', atob(data), '--' + boundary + '--'];
  j = arr.join('\r\n');
  return xhr.sendAsBinary(j);
}

对于 Safari,这些可能性似乎都不存在(尽管很有可能,但我们还不够聪明,无法弄清楚)。一种替代方法是仅使用 base64 编码的数据,Safari 可以肯定地做到这一点。这就是它的样子:

postCanvasToBlobstore = function(url, name, canvas, type) {
  type='image/png'
  var arr, boundary, data, j, xhr;
  data = canvas.toDataURL(type);
  data = data.replace('data:' + type + ';base64,', '');
  xhr = new XMLHttpRequest();
  xhr.open('POST', url, true);
  boundary = 'imaboundary';
  xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
    arr = ['--' + boundary, 'Content-Disposition: form-data; name="' + name + '"; filename="' + name + '"', 'Content-Transfer-Encoding: base64','Content-Type: ' + type, '', data, '--' + boundary + '--'];
  j = arr.join('\r\n');
  return xhr.send(j);
}

现在这确实有效!但是,它仅适用于 AppEngine 工具的开发版本,因为存在一个已知的 blobstore 错误:当您将应用部署到生产环境时,它就会停止工作。当然,在某处调整 POST 代码可能会解决 blobstore 解释数据的问题。请参阅http://code.google.com/p/googleappengine/issues/detail?id=4265了解与此问题相关的 Blobstore 问题。

您可以将上面三个代码示例中的任何一个粘贴到编辑控件中,并可以查看 postCanvasToBlobstore 函数的每个版本会发生什么情况:第一个示例将在 Chrome 中运行,第二个将在 Firefox 中运行(并且是调试应用程序默认的版本to),第三个应该适用于所有三个(但在使用这个生产网站时对它们都不适用,可能是因为 blobstore 错误。)

4

2 回答 2

3

这似乎是生产环境处理方式的一个错误Content-Transfer-Encoding。我已经在内部提交了它,但如果你不想等待它得到解决(我希望你不会),一个解决方法是有序的。

幸运的是,我们最近发布了Files API,这使得以编程方式写入 blobstore 成为可能,我们还将上传请求正文的限制增加到 32MB。只要您的有效负载小于该大小,您就可以编写一个处理程序来接受您最方便的任何格式的上传,然后自己将其存储到 blobstore。我建议保留常规的上传机制,因为它在实际使用时效率更高,但这取决于你。

请记住,对 App Engine API 的单独调用仍然有大小限制;要编写整个文件,您需要多次调用write. 有关更多详细信息,请参阅我对此相关问题的回答。

于 2011-07-04T02:33:37.820 回答
1

我所做的是从canvas到rpc对base64进行分片/分块,通过rpc大约25000个字符,然后我将其分解为900个字符并将它们作为文本存储到数据存储中的tmp表中。完成后,我会进行一些检查以确保其全部存在。然后我将其流式解码到 blobstore 中。

这是一些来源:GAEDatastore

还有更多问题:branflake2267

请为这个问题加注星标。

请在App Engine论坛中发表评论,以便工程师也能看到:

希望有帮助。

于 2011-07-04T03:07:56.553 回答