[英]jQuery .ajax() calls the error function instead of success if the XHR response is an ArrayBuffer representing a JSON object with an error property
Context: I'm trying to implement an ajax download with a progress bar and error handling. 上下文:我正在尝试通过进度条和错误处理来实现Ajax下载。 The front end makes a request to a backend which responds with either a file to download, or an error in the form of a JSON object.
前端向后端发出请求,后端以下载文件或JSON对象形式的错误作为响应。
Problem: I'm using a custom xhr, where the responseType
is set to arraybuffer
. 问题:我使用的是自定义xhr,其中
responseType
设置为arraybuffer
。 This allows me to create a Blob for the file which I then use to present the download. 这使我可以为文件创建一个Blob,然后将其用于显示下载内容。 If the backend responds with a JSON object, I can detect it properly, convert it to a string, and parse it into a native
Object
. 如果后端使用JSON对象响应,我可以正确地检测到它,将其转换为字符串,然后将其解析为本地
Object
。 However, if that Object
contains a property called error
, which I use throughout my application, jQuery calls error()
rather than success()
, and passes one parameter, the value of the error
property. 但是,如果该
Object
包含一个名为error
的属性,我将在整个应用程序中使用它,则jQuery调用error()
而不是success()
,并传递一个参数,即error
属性的值。
What the heck is going on? 到底他妈发生了什么? I've set
dataType: false
to avoid any processing of data, but it seems that jQuery is parsing the arraybuffer, despite the dataType
setting and the response header being set to application/octet-stream
, and deciding that the object, having an error property, requires the error()
function to be called. 我已将
dataType: false
设置为避免对数据进行任何处理,但是尽管dataType
设置和响应标头设置为application/octet-stream
,并且确定该对象有错误,但jQuery似乎正在解析arraybuffer。属性,需要调用error()
函数。
How can I avoid this behavior without changing my backend? 如何在不更改后端的情况下避免这种行为? An alternate implementation could be to leave the
responseType
as text, and then turn the text into a Blob when its a file, but I could never get that to work properly. 另一种实现方式可以是将
responseType
保留为文本,然后在文本成为文件时将其转换为Blob,但我永远无法使其正常工作。
$.ajax({
url: "?download",
method: "POST",
data: {path: this.path, names: names},
dataType: false,
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
myXhr.responseType = "arraybuffer"
myXhr.addEventListener("progress", function(e) {
if (e.lengthComputable) {
var percent = Math.round(e.loaded / e.total * 100);
var text = dir.formatSize(e.loaded, true) + "/" + dir.formatSize(e.total, true)
$("#dl-progress-bar").css("width", percent + "%");
$("#dl-progress-text").text(text)
}
})
return myXhr;
},
success: function(data) {
$("#dl-progress").hide()
$("#dl-progress-bar").css("width", "0")
$("#dl-progress-text").html(" ")
var bufView = new Uint8Array(data);
//Check if the arraybuffer is actually JSON, starting with {"
if (bufView[0] == 123 && bufView[1] == 34 && bufView.length < 200) {
var string = decodeURIComponent(escape(String.fromCharCode.apply(null, Array.prototype.slice.apply(bufView))))
try {
var json = JSON.parse(string)
if (json.success === false && json.error) {
this.error(json.error)
return
}
}
catch (e) {}
}
if (data != null && navigator.msSaveBlob)
return navigator.msSaveBlob(new Blob([data], { type: type }), name)
var a = $("<a style='display: none;'/>")
var blob = new Blob([data], {type: "application/octet-stream"})
var url = window.URL.createObjectURL(blob)
a.attr("href", url)
a.attr("download", filename)
$("body").append(a)
a[0].click()
setTimeout(function() {
window.URL.revokeObjectURL(url);
a.remove()
}, 0)
},
error: function(req, status, error) {
debugger
$("#dl-progress").hide()
$("#dl-progress-bar").css("width", "0")
$("#dl-progress-text").html(" ")
this.ajaxError(req, status, error)
}.bind(this)
})
问题是我没有bind()
我的成功函数,所以它调用了xhr对象的this.error()
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.