Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
251 views
in Technique[技术] by (71.8m points)

javascript - 处理从ajax发布的文件(Handle file download from ajax post)

I have a javascript app that sends ajax POST requests to a certain URL.

(我有一个JavaScript应用程序,可将ajax POST请求发送到某个URL。)

Response might be a JSON string or it might be a file (as an attachment).

(响应可能是JSON字符串,也可能是文件(作为附件)。)

I can easily detect Content-Type and Content-Disposition in my ajax call, but once I detect that the response contains a file, how do I offer the client to download it?

(我可以在ajax调用中轻松检测Content-Type和Content-Disposition,但是一旦检测到响应中包含文件,如何为客户端提供下载文件?)

I've read a number of similar threads here but none of them provide the answer I'm looking for.

(我在这里阅读了许多类似的主题,但是没有一个主题能提供我想要的答案。)

Please, please, please do not post answers suggesting that I shouldn't use ajax for this or that I should redirect the browser, because none of this is an option.

(拜托,拜托,请不要发布暗示我不应该为此使用ajax或重定向浏览器的答案,因为这都不是选项。)

Using a plain HTML form is also not an option.

(也不能使用纯HTML格式。)

What I do need is to show a download dialog to the client.

(我需要做的是向客户端显示一个下载对话框。)

Can this be done and how?

(这可以做到吗?)

  ask by Pavle Predic translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Don't give up so quickly, because this can be done (in modern browsers) using parts of the FileAPI:

(不要这么快就放弃,因为这可以使用FileAPI的一部分来完成(在现代浏览器中):)

var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
    if (this.status === 200) {
        var filename = "";
        var disposition = xhr.getResponseHeader('Content-Disposition');
        if (disposition && disposition.indexOf('attachment') !== -1) {
            var filenameRegex = /filename[^;=
]*=((['"]).*?2|[^;
]*)/;
            var matches = filenameRegex.exec(disposition);
            if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
        }
        var type = xhr.getResponseHeader('Content-Type');

        var blob;
        if (typeof File === 'function') {
            try {
                blob = new File([this.response], filename, { type: type });
            } catch (e) { /* Edge */ }
        }
        if (typeof blob === 'undefined') {
            blob = new Blob([this.response], { 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."
            window.navigator.msSaveBlob(blob, filename);
        } else {
            var URL = window.URL || window.webkitURL;
            var downloadUrl = URL.createObjectURL(blob);

            if (filename) {
                // use HTML5 a[download] attribute to specify filename
                var a = document.createElement("a");
                // safari doesn't support this yet
                if (typeof a.download === 'undefined') {
                    window.location = downloadUrl;
                } else {
                    a.href = downloadUrl;
                    a.download = filename;
                    document.body.appendChild(a);
                    a.click();
                }
            } else {
                window.location = downloadUrl;
            }

            setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup
        }
    }
};
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.send($.param(params));

Here is the old version using jQuery.ajax.

(这是使用jQuery.ajax的旧版本。)

It might mangle binary data when the response is converted to a string of some charset.

(当响应转换为某些字符集的字符串时,它可能会破坏二进制数据。)

$.ajax({
    type: "POST",
    url: url,
    data: params,
    success: function(response, status, xhr) {
        // check for a filename
        var filename = "";
        var disposition = xhr.getResponseHeader('Content-Disposition');
        if (disposition && disposition.indexOf('attachment') !== -1) {
            var filenameRegex = /filename[^;=
]*=((['"]).*?2|[^;
]*)/;
            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 });

        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."
            window.navigator.msSaveBlob(blob, filename);
        } else {
            var URL = window.URL || window.webkitURL;
            var downloadUrl = URL.createObjectURL(blob);

            if (filename) {
                // use HTML5 a[download] attribute to specify filename
                var a = document.createElement("a");
                // safari doesn't support this yet
                if (typeof a.download === 'undefined') {
                    window.location = downloadUrl;
                } else {
                    a.href = downloadUrl;
                    a.download = filename;
                    document.body.appendChild(a);
                    a.click();
                }
            } else {
                window.location = downloadUrl;
            }

            setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup
        }
    }
});

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...