How do I upload a 5 MB file to App Engine BlobStore using XmlHttpRequest 2.0?
We all know that App Engine limits you to 1 MB for most input/output requests. But with the recent BlobStore API, you are allowed to upload large files in full by POSTing to a dynamically generated URL.
According to the sample, here is what the HTML form would look like:
self.response.out.write('<html><body>')
self.response.out.write('<form action="%s" method="POST"
enctype="multipart/form-data">' % upload_url)
self.response.out.write("""Upload File:
<input type="file" name="file"><br>
<input type="submit" name="submit" value="Submit">
</form></body></html>""")
But how can we do this asynchronously using JavaScript techniques introduced with HTML5? This is a snippet of what I have so far:
xhr.open("POST", post_url); // the post URL given by App Engine
xhr.overrideMimeType('text/plain; charset=x-user-defined-binary');
xhr.setRequestHeader('Cache-Control', 'no-cache');
xhr.setRequestHeader('X-File-Name', file.fileName);
// After loading the binary data (last time we only read as base64 string)
// Tell xhr to start the upload
myBinaryDataReader.addEventListener("loadend", function(evt){
xhr.sendAsBinary(evt.target.result);
}, false);
// Initiate the binary reading on the file, when finished it will
// upload asynchronously
myBinaryDataReader.readAsBinaryString(file);
You'll notice that this technique sends the raw binary file as the POST
body. Which is fine, it works without needing the BlobStore for up to 1 MB. In Python, to read the file, I just use:
img_data = self.request.body # got my image data now
However, with BlobStore, I'm supposed to use
upload_files = self.get_uploads('file') # 'file' is file upload field in the form
But I'm not using an HTML form with input type=file, I'm using an XmlHttpRequest -- how can I make App Engine "think" it is a file from an HTML form, and thus "grab" the file data?
My code, u开发者_C百科nmodified, results in an error
File "C:\Python26\lib\cgi.py", line 583, in keys
raise TypeError, "not indexable"
TypeError: not indexable
You may want to check out my blog posts on uploading to the blobstore (1, 2, 3), as well as this recent cookbook post.
The general consensus is that, so far, App Engine's BlobStore upload API will only accept multipart encoded POST data... in other words, an HTML input type=file form. Or, you can use Firefox to read a user's binary file (via drag and drop) with the FileReader API and reconstruct the multipart encoding manually. Then you can submit the data asynchronously with XmlHttpRequest.
As of writing, Chrome and Safari do not support the FileReader object so they cannot break apart binary files and thus not send multipart encoding asynchronously.
Note that the drag N drop + XmlHttpRequest method of uploading files to App Engine still works in all 3 aforementioned browsers if under 1 MB.
精彩评论