Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AjaxForm and app engine blobstore

I'm having some difficulties with AjaxForm file upload and the app engine blobstore. I suspect the difficulty is because the blobstore upload handler (subclass of blobstore_handlers.BlobstoreUploadHandler) mandates a redirect response, rather than returning any content, but I'm not sure. I'm expecting to get an XML document to work with, and it appears to arrive as expected to the browser, but I just can't get hold of it - details below.

My app engine blobstore upload handler is as follows -

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)

The final redirect is to a uri in my application that returns an xml document. Looking at the server output, there is no indication that anything is wrong - the redirect is serviced, and it returns the xml document as expected, with the correct mime type - so the form submission looks good, and the server response to that submission looks good.

My client side code using ajaxForm looks as follows (sorry its a little obtuse, I dont think the problem is here though)-

// 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));
         }
      });
    });

I set the 'action' on the form (and enable the button) afterwards -

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

I'm using a little google closure in there as well for logging and exposing objects. Everything looks good - as expected it is posting correctly to the server, and the success function is called. If I watch the document structure in Chrome dev tools, I can see the iFrame being created briefly to handle the file upload and response.

The problem is that I never get the xml document in the response. The log output is as follows -

[ 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]

The complaint by chrome about the mime type is probably super relevant, but I'm not making the connection :) - at least it means that it is getting the xml document at some point. In Chrome resources view, you can see the POST, and that the response is a 302 redirect, and then the subsequent GET request - the header of which looks fine -

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 resources view won't show me the content of that document (just blank) but firefox does and the xml document looks fine. Firefox gives the same end result however - null for the ajaxSubmit() responseText.

I figure I'm just having a brain fade here somewhere, but it's really got me stumped. Any pointers for getting that xml document would be great - cheers,

Colin

like image 990
hawkett Avatar asked Jun 20 '10 20:06

hawkett


2 Answers

Here's a method I've used (only tested in Chrome) slightly modified. It's not AjaxForm but it works.

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);
}

The entityKey is available as a param on the server. The 'files' parameter comes from the 'files' attribute of the file-type input form element (as an array to support multiple). The 'progress_callback' parameter is a function that takes an object that has (at least) a 'loaded' and a 'total' field (unit is bytes). It doesn't care about the server response.

like image 190
sje397 Avatar answered Nov 09 '22 01:11

sje397


here is how i solved it. I added a random id generatated in javascript send along with file. once the upload complete, configure my server to remember the association of that random id and uploaded file for a while. I send another query to a predefine url like mysite.com/blobdata/that_random_id_i_renerated to request the file just uploaded. it worked.

like image 32
iamgopal Avatar answered Nov 09 '22 02:11

iamgopal