I have a binary file (python pickle
file, to be exact). Whenever such a file is requested, I create one on server side, and then send it to the client via flask's send_file
as an AJAX request.
Next, I need to download this file automatically to the client side, so I have used this answer.
The problem is that, the created file on the server normally has a size 300 Bytes, and the file downloaded on the client side is of the size >500 Bytes. Plus whenever I try to reuse the pickle file, it doesn't load, giving the error:
_pickle.UnpicklingError: invalid load key, '\xef'.
Whereas, the server file is loaded seamlessly. So, the problem is, the client side file is corrupted, while in transmission. I think the js blob
might be the culprit.
Has anyone seen something like this before?
Server side code handling the AJAX (flask)
@app.route("/_exportTest",methods=['POST'])
def exportTest():
index = int(request.form['index'])
path = g.controller.exportTest(testID=index)
logger.debug("Test file path :"+path)
return send_file(path) #this is wrong somehow
Regarding the exportTest
function:
def exportTest(self,testName):
dic = dict()
dic['screenShot'] = self.screenShot #string
dic['original_activity'] = self.original_activity #string
dic['steps'] = self.steps #list of tuples of strings
if self.exportFilePath=='.': #this is the case which will be true
filePath = os.path.join(os.getcwd(),testName)
else:
filePath = os.path.join(os.getcwd(),self.exportFilePath,testName)
logger.debug("filePath :"+filePath)
try:
pickle.dump(dic,open(filePath,"wb"),protocol=pickle.HIGHEST_PROTOCOL)
except Exception as e:
logger.debug("Error while pickling Test.\n Error :"+str(e)) #No such error was printed
return filePath
Client side code:
$.ajax({
type: "POST",
// url: "/_exportTest",
url:"/_exportTest",
data:{index:testIndex},
success: function(response, status, xhr) {
// check for a filename
var filename = "TEST_"+testIndex+".tst";
var disposition = xhr.getResponseHeader('Content-Disposition');
if (disposition && disposition.indexOf('attachment') !== -1) {
var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
}
var type = xhr.getResponseHeader('Content-Type');
var blob = new Blob([response],{type:type});//, { type: type });
console.log("Binary type :"+type) ;
if (typeof window.navigator.msSaveBlob !== 'undefined') {
// IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
console.log("WINDOW NAVIGATION MSSAVEBLOB type if undefined") ;
window.navigator.msSaveBlob(blob, filename);
}
else {
console.log("ELSE1")
var URL = window.URL || window.webkitURL;
var downloadUrl = URL.createObjectURL(blob);
if (filename) {
console.log("Filename exists") ;
// use HTML5 a[download] attribute to specify filename
var a = document.createElement("a");
// safari doesn't support this yet
if (typeof a.download === 'undefined') {
console.log("typeof a.download is undefined") ;
window.location.href = downloadUrl;
} else {
console.log("typeof a.download is not undefined") ;
a.href = downloadUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
}
} else {
console.log("Filename does not exist") ;
window.location.href = downloadUrl;
}
// window.location.href = downloadUrl;
setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup
}
}
});
this is the correct way
- not sure whatthis
is, as you've shown no code – AdjointXMLHttpRequest
,jQuery.ajax
, or some other wrapper? Also try sending a mime type on the server side:send_file(path, 'application/octet-stream')
. – BusterjQuery.ajax
. I tried this, but got the same result. Curiously, in order to isolate the problem, I had created another route_testURL
just for this, which simply didsend_file(<file-path>)
. Now, when I tried to do aget
then it downloaded the correct file. But when I used your answer's code, it again increased size. So, could it be possible that there is something mangling with the byte string? – Credo