AjaxForm和应用引擎Blobstore

16

我在使用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));
         }
      });
    });

我事后设置了表单上的“action”(并启用了按钮) -

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

我也使用了一些Google Closure用于日志记录和对象公开。 一切看起来很好-预期它会正确地发布到服务器,并调用成功函数。 如果我在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也会得到同样的结果-null用于ajaxSubmit()的responseText。

我想我可能只是在某个地方犯了脑抽,但这真的让我困惑了。任何获取xml文档的指针都将是极好的-谢谢,

科林


我猜测Ajaxform不能正确处理重定向 - 无论是自己处理还是因为它使用的Flash组件不能处理它们。尝试将上传处理程序更改为常规请求处理程序,并直接返回文档而不是重定向,看看是否有任何区别 - 这至少可以告诉您是否是重定向的问题。 - Nick Johnson
是的,好的 - 确认了建议的重定向方式(它不使用Flash)。为什么Blobstore UploadHandler要求重定向?有人用Blobstore实现了ajax式上传吗?即用户无需经历重定向或页面刷新?谢谢。 - hawkett
作者确认无法追踪重定向。似乎强制重定向行为在Blobstore API中有些过度? - hawkett
成功:function(responseText,statusText,xhr,$form){ log.info(“响应:”+ responseText +“,状态文本:”+ statusText +“,xhr:”+ goog.debug.expose(xhr)+“,表单:”+ goog.debug.expose($ form)); } 这看起来可能不起作用,因为它将响应解释为xml,我认为您必须使用jquery解析xml并检索要使用的数据。例如。 <code> $(responseText).find('tagname').text(); </code> - sillyMunky
1
responseText为null,不是一个XML文档。这是因为响应是重定向(302),没有正文。 - hawkett
3个回答

4

这是我使用过的一种方法(仅在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”字段(单位为字节)。它不关心服务器响应。

好的,所以不要等待响应,使用进度回调来识别上传何时完成(loaded == total?),然后单独查询更新的实体 - 就像你说的那样,完全忽略服务器响应?谢啦。 - hawkett

1

这是我解决它的方法。我在上传文件时添加了一个由JavaScript生成的随机ID,一起发送。一旦上传完成,配置我的服务器在一段时间内记住该随机ID和已上传文件之间的关联。我向预定义的URL发送另一个查询,例如mysite.com/blobdata/that_random_id_i_renerated,以请求刚刚上传的文件。它有效地解决了问题。


0

这个问题几乎肯定不是Chrome的问题 - 它在其他浏览器中也会发生。问题取决于你如何看待它,要么是blobstore API强制重定向,要么是AjaxForm没有跟随该重定向。在没有来自Google的任何理由的情况下,我倾向于前者 - 似乎他们为了没有理由而创造了一个障碍。 - hawkett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接