JavaScript Blob下载一个二进制文件,创建损坏的文件 [英] JavaScript Blob to download a binary file creating corrupted files
问题描述
我有一个二进制文件(准确地说是python pickle
文件).每当请求这样的文件时,我都会在服务器端创建一个文件,然后将其作为AJAX请求通过flask的send_file
发送到客户端.
接下来,我需要将此文件自动下载到客户端,因此我使用了此答案.. >
问题在于,在服务器上创建的文件通常具有300字节的大小,而在客户端下载的文件的大小则大于500字节.另外,每当我尝试重用pickle文件时,该文件都不会加载,并显示错误消息:
_pickle.UnpicklingError: invalid load key, '\xef'.
因此,服务器文件是无缝加载的.因此,问题在于,客户端文件在传输时已损坏.我认为js blob
可能是罪魁祸首.
以前有没有人看过类似的东西?
处理AJAX的服务器端代码(烧瓶)
@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
关于exportTest
功能:
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
客户端代码:
$.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
}
}
});
奇怪的是,我正在研究此答案,该方法有效.因此,我添加了:
xhrFields: {
responseType:'blob'
},
在AJAX请求中,它为我解决了问题.
我完全不知道,为什么这样做有效,所以有人能给出比这个更好的答案吗?
在 MDN文档中:
The values supported by responseType are the following:
An empty responseType string is treated the same as "text", the default type.
arraybuffer
The response is a JavaScript ArrayBuffer containing binary data.
blob
The response is a Blob object containing the binary data.
...
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
}
}
});
Weirdly enough, I was looking into this answer, which worked. So, I added :
xhrFields: {
responseType:'blob'
},
in the AJAX request, which solved the problem for me.
I have absolutely no idea, why this worked, so can someone give a better answer than this?
At MDN Docs:
The values supported by responseType are the following:
An empty responseType string is treated the same as "text", the default type.
arraybuffer
The response is a JavaScript ArrayBuffer containing binary data.
blob
The response is a Blob object containing the binary data.
...
这篇关于JavaScript Blob下载一个二进制文件,创建损坏的文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!