Downloading the requested file using XMLHttpRequest

I know that the jQuery ajax method cannot handle downloads, and I do not want to add a jQuery plugin for this.

I want to know how to send POST data using XMLHttpRequest to upload a file.

Here is what I tried:

var postData = new FormData(); postData.append('cells', JSON.stringify(output)); var xhr = new XMLHttpRequest(); xhr.open('POST', '/export/', true); xhr.setRequestHeader("X-CSRFToken", csrftoken); xhr.responseType = 'arraybuffer'; xhr.onload = function (e) { console.log(e); console.log(xhr); } xhr.send(postData); 

I am working with Django, and the file seems to be sending successfully to the client. On the Network tab in Chrome, I see gibberish on the preview tab (what I expect). But I want to send a zip file, not a text representation of the zip file. Here is the end of Django:

 wrapper = FileWrapper(tmp_file) response = HttpResponse(wrapper, content_type='application/zip') response['Content-Disposition'] = "attachment; filename=export.zip" response['Content-Length'] = tmp_file.tell() return response 

I searched for hours without finding a suitable example of how to do this with XMLHttpRequests. I do not want to create the correct html form with the POST action, because the form data is quite large and dynamically created.

Is there something wrong with this code? Is something missing? I just don't know how to actually send data to the client as a download.

+11
javascript post django
source share
3 answers

An XHR request will not load the file. I cannot find an explicit requirement, but the W3C doc on XMLHttpRequest does not describe any special reaction to the content layout = responses to attachments either

You can upload the file using window.open () on a separate tab if it was not a POST request. It was suggested here to use a hidden form with target = _blank

UPD : this answer has not been accurate since the advent of the Blob API . Please see Stephen for details.

+10
source

If, before sending a request, you set the XMLHttpRequest.responseType property to 'blob' , then when you receive a response, it will be presented as a blob. Then you can save the blob to a temporary file and go to it.

 var postData = new FormData(); postData.append('cells', JSON.stringify(output)); var xhr = new XMLHttpRequest(); xhr.open('POST', '/export/', true); xhr.setRequestHeader('X-CSRFToken', csrftoken); xhr.responseType = 'blob'; xhr.onload = function (this, event) { var blob = this.response; var contentDispo = this.getResponseHeader('Content-Disposition'); // https://stackoverflow.com/a/23054920/ var fileName = contentDispo.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)[1]; saveOrOpenBlob(blob, fileName); } xhr.send(postData); 

And here is an example implementation of saveOrOpenBlob :

 function saveOrOpenBlob(blob, fileName) { window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem; window.requestFileSystem(window.TEMPORARY, 1024 * 1024, function (fs) { fs.root.getFile(fileName, { create: true }, function (fileEntry) { fileEntry.createWriter(function (fileWriter) { fileWriter.addEventListener("writeend", function () { window.location = fileEntry.toURL(); }, false); fileWriter.write(blob, "_blank"); }, function () { }); }, function () { }); }, function () { }); } 

If you do not need the browser to navigate to the file when it is available for viewing, then making a method that always saves directly to a file is much simpler:

 function saveBlob(blob, fileName) { var a = document.createElement('a'); a.href = window.URL.createObjectURL(blob); a.download = fileName; a.dispatchEvent(new MouseEvent('click')); } 
+17
source

 download: function(){ var postData = new FormData(); var xhr = new XMLHttpRequest(); xhr.open('GET', downloadUrl, true); xhr.responseType = 'blob'; xhr.onload = function (e) { var blob = xhr.response; this.saveOrOpenBlob(blob); }.bind(this) xhr.send(postData); } saveOrOpenBlob: function(blob) { var assetRecord = this.getAssetRecord(); var fileName = 'Test.mp4' var tempEl = document.createElement("a"); document.body.appendChild(tempEl); tempEl.style = "display: none"; url = window.URL.createObjectURL(blob); tempEl.href = url; tempEl.download = fileName; tempEl.click(); window.URL.revokeObjectURL(url); }, 

Try this, it works for me.

0
source

All Articles