简体   繁体   中英

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. 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.

Problem: I'm using a custom xhr, where the responseType is set to arraybuffer . This allows me to create a Blob for the file which I then use to present the download. 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 . 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.

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.

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.

$.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("&nbsp;")
                this.ajaxError(req, status, error)
            }.bind(this)
        })

问题是我没有bind()我的成功函数,所以它调用了xhr对象的this.error()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM