【问题标题】:AjaxForm and app engine blobstoreAjaxForm 和应用引擎 blobstore
【发布时间】:2011-03-06 02:05:10
【问题描述】:

我在使用 AjaxForm 文件上传和应用引擎 blobstore 时遇到了一些困难。我怀疑困难是因为 blobstore 上传处理程序(blobstore_handlers.BlobstoreUploadHandler 的子类)要求重定向响应,而不是返回任何内容,但我不确定。我期望得到一个 XML 文档来使用,它似乎按预期到达浏览器,但我无法掌握它 - 详情如下。

我的应用引擎 blobstore 上传处理程序如下 -

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
  def post(self):
    upload_files = self.get_uploads('file')  # 'file' is file upload field in the form
    blob_info = upload_files[0]

    entity_key = self.request.get("entityKey")

    // Update a datastore entity with the blobkey (not shown)

    // redirect to the uri for the updated entity
    self.redirect('%s.xml' % entity_key)

最终重定向到我的应用程序中返回 xml 文档的 uri。查看服务器输出,没有任何迹象表明有任何问题 - 重定向服务,它按预期返回 xml 文档,具有正确的 mime 类型 - 所以表单提交看起来不错,服务器对该提交的响应看起来不错。

我使用 ajaxForm 的客户端代码如下所示(抱歉有点迟钝,但我认为问题不在这里)-

// Create the form
var dialogForm = $("<form method='POST' enctype='multipart/form-data'>")
   .append("<span>Upload File: </span><input type='file' name='file'/><br>")
   .append("<input type='hidden' name='entityKey' value='" + entityKey + "'/>")
   .append("<input type='hidden' name='entityField' value='image'/>")
   .append("<input type='button' value='Wait...' disabled='disabled'/>");;

dialogForm.ajaxForm();

// Turn the form button into a nice jQuery UI button and add a click handler
$("input[type=button]", dialogForm[0]).button()
   .click(function() {
      log.info("Posting to : " + dialogForm.attr('action'));
      dialogForm.ajaxSubmit({
         success: function(responseText, statusText, xhr, $form) {
            log.info("Response: " + responseText + ", statusText: " + statusText + ", xhr: " + goog.debug.expose(xhr) + ", form:" + goog.debug.expose($form));
         }
      });
    });

之后我在表单上设置“操作”(并启用按钮)-

$.get('/blob_upload_url', function(data) {
  dialogForm.attr("action", data);
  $("input[type=button]", dialogForm[0]).attr("value", "Upload").button("option", "disabled", false);
};

我在那里使用了一个小的 google 闭包来记录和公开对象。一切看起来都很好 - 正如预期的那样,它正确地发布到服务器,并调用了成功函数。如果我在 Chrome 开发工具中查看文档结构,我可以看到正在创建的 iFrame 用于处理文件上传和响应。

问题是我从来没有在响应中得到 xml 文档。日志输出如下-

[ 18.642s] [Panel] Response: null, statusText: success, xhr: 0 = [object HTMLFormElement]
length = 1
selector = 
jquery = 1.4.2, form:0 = [object HTMLFormElement]
length = 1
selector = 
jquery = 1.4.2
Resource interpreted as document but transferred with MIME type application/xml [ABCdefGH]

chrome 对 mime 类型的抱怨可能非常相关,但我没有建立联系 :) - 至少这意味着它在某个时候正在获取 xml 文档。在 Chrome 资源视图中,您可以看到 POST,并且响应是 302 重定向,然后是后续的 GET 请求 - 其标头看起来不错 -

Request URL:http://localhost:8081/_ah/upload/ABCdefGH
Request Method:GET
Status Code:200 OK
Request Headers
Referer:http://localhost:8081/
User-Agent:Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.70 Safari/533.4
Response Headers
Cache-Control:no-cache
Content-Length:2325
Content-Type:application/xml
Date:Sun, 20 Jun 2010 20:47:39 GMT
Expires:Fri, 01 Jan 1990 00:00:00 GMT
Server:Development/1.0

Chrome 资源视图不会向我显示该文档的内容(只是空白),但 Firefox 会显示,并且 xml 文档看起来不错。然而,Firefox 给出了相同的最终结果 - ajaxSubmit() responseText 为 null。

我想我只是在某个地方出现了大脑衰退,但这真的让我很难过。获取该 xml 文档的任何指针都会很棒 - 干杯,

科林

【问题讨论】:

  • 我猜测 Ajaxform 不能正确处理重定向 - 无论是它自己,还是因为它使用了一个无法处理它们的 flash 组件。尝试将您的上传处理程序更改为常规请求处理程序并直接返回文档而不是重定向,看看这是否有任何区别 - 这至少会告诉您它是否是重定向。
  • 是的,确认它是按照建议的重定向(它不使用闪存)。为什么 blobstore UploadHandler 要求重定向?有人使用 blobstore 进行 ajax 样式上传吗?即用户没有体验到重定向或页面刷新?谢谢。
  • forum.jquery.com/topic/… - 作者确认它不能追逐重定向。似乎 forced 重定向行为对于 blobstore API 来说太过分了?
  • 成功: function(responseText, statusText, xhr, $form) { log.info("Response: " + responseText + ", statusText: " + statusText + ", xhr: " + goog.debug.expose(xhr) + ", form:" + goog.debug.expose($form)); } 这看起来可能行不通,因为它将响应解释为 xml,我认为您必须使用 jquery 来解析 xml 并检索要使用的数据。例如 $(responseText).find('tagname').text();
  • responseText 为空,不是 xml 文档。这是因为响应是重定向 (302) 并且没有正文。

标签: jquery google-app-engine ajaxform


【解决方案1】:

这是我使用的一种方法(仅在 Chrome 中测试过),稍作修改。它不是 AjaxForm,但它可以工作。

function upload_files(entityKey, files, url, progress_callback) {
  var xhr = new XMLHttpRequest(), formData = new FormData();
  xhr.upload['onprogress'] = progress_callback;

  formData.append('entityKey', entityKey);
  $.each(files, function(i, file) { formData.append('file[]', file);});

  xhr.open("post", url, true);
  xhr.setRequestHeader("Cache-Control", "no-cache");
  xhr.send(formData);
}

entityKey 可作为服务器上的参数使用。 'files' 参数来自文件类型输入表单元素的 'files' 属性(作为支持多个的数组)。 'progress_callback' 参数是一个函数,它接受一个对象,该对象具有(至少)一个 'loaded' 和一个 'total' 字段(单位是字节)。它不关心服务器响应。

【讨论】:

  • 好的,所以不要等待响应,而是使用进度回调来识别上传何时完成(已加载 == 总计?),然后单独查询更新的实体 - 正如您所说,完全忽略服务器响应?塔。
【解决方案2】:

这就是我解决它的方法。我添加了一个在 javascript 中生成的随机 ID,并与文件一起发送。上传完成后,将我的服务器配置为记住该随机 id 和上传文件的关联一段时间。我向 mysite.com/blobdata/that_random_id_i_renerated 等预定义 URL 发送另一个查询,以请求刚刚上传的文件。成功了。

【讨论】:

    【解决方案3】:

    如果你在同一个问题上停留了 5 个月。我认为你应该在这里问:

    http://www.google.com/support/forum/p/Chrome/

    【讨论】:

    • 这个问题几乎可以肯定不是 chrome 问题 - 它发生在其他浏览器中。问题取决于您如何看待它,要么是 blobstore api 强制重定向,要么是 AjaxForm 不追逐该重定向。在谷歌没有任何理由的情况下,我倾向于前者 - 似乎他们无缘无故地创造了一个可以跳过的箍。
    猜你喜欢
    • 2015-10-05
    • 2011-04-18
    • 1970-01-01
    • 2014-04-04
    • 2012-01-19
    • 2013-11-12
    • 2015-09-03
    • 2013-03-12
    • 2013-03-28
    相关资源
    最近更新 更多