2

使用 MVC 4.0,我使用以下代码从 ajax 源(使用最新的 firefox)从服务器创建下载文件:

如果输出涉及的是文本文件(例如 csv 或 txt 文件),这可以正常工作,但是,当涉及到 zip 或 xlsx 等文件时,下载的文件似乎与原始源不同(即在服务器中生成的 zip 为 15K ,但下载的是26K)

我已经挣扎了几天,请问是否有人应该解释一下为什么它适用于 csv/text 文件,但不适用于 zip 或 xlsx 文件?

非常感谢

控制器:

Public Function download(dataIn As myObject) As ActionResult
        'some processing
        'generated zip files and return with the full path            
        Dim zipFullPath = generateFiles(dataIn)

        Response.Clear()
        Response.ContentType = "application/zip"           
        Response.AddHeader("Content-Disposition", "attachment; filename=Out.zip")
        Dim fileLength = New IO.FileInfo(zipFullPath).Length
        'fileLength  reads about 15K of data
        Response.AddHeader("Content-Length", fileLength)
        Response.TransmitFile(zipFullPath)
        Response.End()
        Return View()
    End Function

JavaScript:

$.ajax({
    type: "POST",
    url: "reports/download",
    data: jData,
    contentType: "application/json; charset=utf-8",
    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[^;=\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 });

        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();

                    //Here is the problem, the original is about 15k,  
                    // but the download file is about 26K

                }
            } else {                    
                window.location = downloadUrl;
            }

            setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup
        }
    },
    error: function (data) {
        alert('Error');
    }
});
4

1 回答 1

2

目前 jQuery ajax 只能处理文本响应,这就是为什么你的文本文件可以工作但你的二进制文件失败的原因。
要从 ajax 下载非文本文件,请使用 XMLHttpRequest 对象并指定 responseType,例如blobarraybuffer

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
    if (this.readyState == 4 && this.status == 200){
        ...
        var blob = this.response; //save the blob as usual
        ...
    }
}
xhr.open('POST', 'reports/download');
xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
xhr.responseType = 'blob'; // the response will be a blob and not text
xhr.send(jData);      
于 2015-05-14T14:53:12.910 回答