处理从ajax帖子下载的文件

时间:2013-04-18 14:48:45

标签: javascript jquery ajax

我有一个javascript应用程序,它将ajax POST请求发送到某个URL。响应可能是JSON字符串,也可能是文件(作为附件)。我可以在我的ajax调用中轻松检测Content-Type和Content-Disposition,但是一旦我检测到响应包含文件,我该如何让客户端下载它?我在这里读过很多类似的帖子,但没有一个提供我正在寻找的答案。

拜托,请不要发布答案,建议我不要使用ajax或者我应该重定向浏览器,因为这都不是一个选项。使用纯HTML表单也不是一种选择。我需要的是向客户端显示下载对话框。可以这样做吗?

编辑:

显然,这不可能做到,但有一个简单的解决方法,如接受的答案所示。对于将来遇到这个问题的人来说,我就是这样解决的:

$.ajax({
    type: "POST",
    url: url,
    data: params,
    success: function(response, status, request) {
        var disp = request.getResponseHeader('Content-Disposition');
        if (disp && disp.search('attachment') != -1) {
            var form = $('<form method="POST" action="' + url + '">');
            $.each(params, function(k, v) {
                form.append($('<input type="hidden" name="' + k +
                        '" value="' + v + '">'));
            });
            $('body').append(form);
            form.submit();
        }
    }
});

基本上,只需生成一个HTML表单,其中包含与AJAX请求中使用的相同的参数并提交它。

20 个答案:

答案 0 :(得分:486)

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

编辑2017-09-28:更新后使用File构造函数,以便在Safari&gt; = 10.1中使用。

编辑2015-10-16:jQuery ajax无法正确处理二进制响应(无法设置responseType),因此最好使用普通的XMLHttpRequest调用。

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[^;=\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 = typeof File === 'function'
            ? new File([this.response], filename, { type: type })
            : 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));

这是使用jQuery.ajax的旧版本。当响应转换为某个字符串的字符串时,它可能会破坏二进制数据。

$.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[^;=\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();
                }
            } else {
                window.location = downloadUrl;
            }

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

答案 1 :(得分:105)

创建表单,使用POST方法,提交表单 - 不需要iframe。当服务器页面响应请求时,为文件的mime类型写一个响应头,它将显示一个下载对话框 - 我已经多次这样做了。

您想要内容类型的应用程序/下载 - 只需搜索如何为您正在使用的任何语言提供下载。

答案 2 :(得分:31)

您使用的是哪种服务器端语言?在我的应用程序中,我可以通过在PHP的响应中设置正确的标题来轻松地从AJAX调用下载文件:

设置标头服务器端

header("HTTP/1.1 200 OK");
header("Pragma: public");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");

// The optional second 'replace' parameter indicates whether the header
// should replace a previous similar header, or add a second header of
// the same type. By default it will replace, but if you pass in FALSE
// as the second argument you can force multiple headers of the same type.
header("Cache-Control: private", false);

header("Content-type: " . $mimeType);

// $strFileName is, of course, the filename of the file being downloaded. 
// This won't have to be the same name as the actual file.
header("Content-Disposition: attachment; filename=\"{$strFileName}\""); 

header("Content-Transfer-Encoding: binary");
header("Content-Length: " . mb_strlen($strFile));

// $strFile is a binary representation of the file that is being downloaded.
echo $strFile;

这实际上会将浏览器“重定向”到这个下载页面,但正如@ahren alread在评论中所说,它不会离开当前页面。

这一切都与设置正确的标题有关,因此我确信如果它不是PHP,您将找到适合您正在使用的服务器端语言的解决方案。

处理响应客户端

假设您已经知道如何进行AJAX调用,则在客户端执行对服务器的AJAX请求。然后,服务器生成一个链接,从该文件可以下载该文件,例如,您要指向的“转发”网址。 例如,服务器响应:

{
    status: 1, // ok
    // unique one-time download token, not required of course
    message: 'http://yourwebsite.com/getdownload/ska08912dsa'
}

处理响应时,在您的身体中注入一个iframe并将iframe的SRC设置为您刚刚收到的URL(为了方便本例,使用jQuery):< / p>

$("body").append("<iframe src='" + data.message +
  "' style='display: none;' ></iframe>");

如果你设置了如上所示的正确标题,iframe将强制下载对话框,而不会将浏览器导航离开当前页面。

注意

与您的问题有关的额外补充;我认为在使用AJAX技术请求内容时总是返回JSON。收到JSON响应后,您可以决定客户端如何处理它。也许,例如,稍后您希望用户单击URL的下载链接而不是直接强制下载,在当前设置中,您必须同时更新客户端和服务器端。

答案 3 :(得分:31)

我遇到了同样的问题并成功解决了它。我的用例就是这个。

将JSON数据发布到服务器并接收excel文件。 该excel文件由服务器创建,并作为对客户端的响应返回。将该响应下载为具有浏览器中自定义名称的文件

$("#my-button").on("click", function(){

// Data to post
data = {
    ids: [1, 2, 3, 4, 5]
};

// Use XMLHttpRequest instead of Jquery $ajax
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    var a;
    if (xhttp.readyState === 4 && xhttp.status === 200) {
        // Trick for making downloadable link
        a = document.createElement('a');
        a.href = window.URL.createObjectURL(xhttp.response);
        // Give filename you wish to download
        a.download = "test-file.xls";
        a.style.display = 'none';
        document.body.appendChild(a);
        a.click();
    }
};
// Post data to URL which handles post request
xhttp.open("POST", excelDownloadUrl);
xhttp.setRequestHeader("Content-Type", "application/json");
// You should set responseType as blob for binary responses
xhttp.responseType = 'blob';
xhttp.send(JSON.stringify(data));
});

上面的代码片段正在执行以下操作

  • 使用XMLHttpRequest将数组作为JSON发布到服务器。
  • 在将内容作为blob(二进制)获取后,我们正在创建一个可下载的URL并将其附加到不可见的“a”链接,然后单击它。

这里我们需要在服务器端仔细设置一些东西。我在Python Django HttpResponse中设置了几个标题。如果使用其他编程语言,则需要相应地设置它们。

# In python django code
response = HttpResponse(file_content, content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")

由于我在这里下载xls(excel),我将contentType调整为高于1。您需要根据文件类型进行设置。您可以使用此技术下载任何类型的文件。

答案 4 :(得分:20)

对于那些从Angular角度寻求解决方案的人来说,这对我有用:

$http.post(
  'url',
  {},
  {responseType: 'arraybuffer'}
).then(function (response) {
  var headers = response.headers();
  var blob = new Blob([response.data],{type:headers['content-type']});
  var link = document.createElement('a');
  link.href = window.URL.createObjectURL(blob);
  link.download = "Filename";
  link.click();
});

答案 5 :(得分:13)

以下是我的工作方式 https://stackoverflow.com/a/27563953/2845977

&#13;
&#13;
$.ajax({
  url: '<URL_TO_FILE>',
  success: function(data) {
    var blob=new Blob([data]);
    var link=document.createElement('a');
    link.href=window.URL.createObjectURL(blob);
    link.download="<FILENAME_TO_SAVE_WITH_EXTENSION>";
    link.click();
  }
});
&#13;
&#13;
&#13;

使用download.js

更新了答案

&#13;
&#13;
$.ajax({
  url: '<URL_TO_FILE>',
  success: download.bind(true, "<FILENAME_TO_SAVE_WITH_EXTENSION>", "<FILE_MIME_TYPE>")
});
&#13;
&#13;
&#13;

答案 6 :(得分:12)

我看到你已经找到了一个解决方案,但是我只是想添加一些信息,这可能有助于某些人尝试通过大的POST请求来实现同样的目标。

几个星期前我遇到了同样的问题,确实无法实现清洁&#34;通过AJAX下载,Filament Group创建了一个jQuery插件,它完全按照您已经发现的方式运行,它被称为jQuery File Download但是这种技术有一个缺点。

如果您通过AJAX发送大量请求(比如文件+ 1MB),则会对响应能力产生负面影响。在慢速Internet连接中,您必须等待很多,直到发送请求并等待文件下载。它不像是一个瞬间&#34;点击&#34; =&GT; &#34;弹出&#34; =&GT; &#34;下载开始&#34;。它更像是&#34;点击&#34; =&GT; &#34;等到发送数据&#34; =&GT; &#34;等待回应&#34; =&GT; &#34;下载开始&#34;这使得它看起来文件的大小加倍,因为你必须等待通过AJAX发送请求并将其作为可下载文件取回。

如果你正在使用<1MB的小文件,你就不会注意到这一点。但正如我在自己的应用程序中发现的那样,对于更大的文件大小,它几乎无法忍受。

我的应用程序允许用户导出动态生成的图像,这些图像通过POST64格式的POST请求发送到服务器(这是唯一可能的方式),然后处理并以.png,.jpg的形式发送给用户文件,图像的base64字符串+ 1MB都很大,这迫使用户等待文件开始下载所需的时间。在慢速的互联网连接中,它真的很烦人。

我的解决方案是临时将文件写入服务器,一旦准备就绪,动态生成一个按钮形式的文件链接,该按钮在&#34;之间发生变化,请等待...&#34;和&#34;下载&#34;状态,同时,在预览弹出窗口中打印base64图像,以便用户可以右键单击&#34;并保存。这使得所有等待时间对用户来说更加可以忍受,并且还可以加快速度。

2014年9月30日更新:

  

自从我发布这个月以来已经过了几个月,最后我找到了一个更好的方法来加快使用big base64字符串的速度。我现在将base64字符串存储到数据库中(使用longtext或longblog字段),然后我通过jQuery文件下载传递其记录ID,最后在下载脚本文件中我使用此ID查询数据库以提取base64字符串并将其传递给下载功能。

下载脚本示例:

<?php
// Record ID
$downloadID = (int)$_POST['id'];
// Query Data (this example uses CodeIgniter)
$data       = $CI->MyQueries->GetDownload( $downloadID );
// base64 tags are replaced by [removed], so we strip them out
$base64     = base64_decode( preg_replace('#\[removed\]#', '', $data[0]->image) );
// This example is for base64 images
$imgsize    = getimagesize( $base64 );
// Set content headers
header('Content-Disposition: attachment; filename="my-file.png"');
header('Content-type: '.$imgsize['mime']);
// Force download
echo $base64;
?>

我知道这超出了OP所要求的范围,但我觉得用我的发现更新我的答案会更好。当我在寻找问题的解决方案时,我阅读了很多&#34;从AJAX POST数据下载&#34; 线程,这些线程没有给我我想要的答案,我希望这些信息可以帮助那些希望实现此类目标的人。

答案 7 :(得分:6)

对于那些寻求更现代方法的人,可以使用fetch(url, { body: JSON.stringify(data), method: 'POST', headers: { 'Content-Type': 'application/json; charset=utf-8' }, }) .then(response => response.blob()) .then(response => { const blob = new Blob([response], {type: 'application/application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}); const downloadUrl = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = downloadUrl; a.download = "file.xlsx"; document.body.appendChild(a); a.click(); }) 。以下示例显示了如何下载电子表格文件。使用以下代码即可轻松完成。

XMLHttpRequest

我认为,这种方法比其他jQuery解决方案更容易理解。而且,它的语法与url方法类似,而无需添加任何其他库。

当然,我建议您检查一下要开发的浏览器,因为这种新方法不适用于IE。您可以在以下[link] [1]中找到完整的浏览器兼容性列表。

重要:在此示例中,我正在向侦听给定url的服务器发送JSON请求。必须设置此Content-Type,在我的示例中,我假设您知道这一部分。另外,请考虑您的请求正常工作所需的标头。由于我正在发送JSON,因此必须添加application/json; charset=utf-8标头并将其设置为{{1}},以使服务器知道它将接收的请求的类型。

答案 8 :(得分:5)

我想指出在接受的答案中使用该技术时出现的一些困难,即使用表格帖子:

  1. 您无法在请求中设置标头。如果您的身份验证架构涉及标头,在Authorization标头中传递了Json-Web-Token,您将必须找到其他方式来发送它,例如作为查询参数。

  2. 您无法确定请求何时完成。好吧,你可以使用一个响应设置的cookie,就像jquery.fileDownload所做的那样,但它是完美的FAR。它不适用于并发请求,如果响应永远不会到达,它将会中断。

  3. 如果服务器响应错误,用户将被重定向到错误页面。

  4. 您只能使用form支持的内容类型。这意味着您无法使用JSON。

  5. 我最终使用在S3上保存文件的方法并发送预先签名的URL来获取文件。

答案 9 :(得分:3)

这是一个3岁的问题,但今天我遇到了同样的问题。我查看了您编辑的解决方案,但我认为它可能会牺牲性能,因为它必须提出双重请求。因此,如果任何人需要另一个并不意味着两次调用该服务的解决方案,那么这就是我这样做的方式:

<form id="export-csv-form" method="POST" action="/the/path/to/file">
    <input type="hidden" name="anyValueToPassTheServer" value="">
</form>

此表单仅用于调用服务并避免使用window.location()。之后,您只需要从jquery提交表单,以便调用服务并获取文件。它非常简单,但这样您就可以使用 POST 进行下载。我现在,如果您拨打的服务是 GET ,这可能会更容易,但这不是我的情况。

答案 10 :(得分:3)

以下是我使用临时隐藏表单的解决方案。

//Create an hidden form
var form = $('<form>', {'method': 'POST', 'action': this.href}).hide();

//Add params
var params = { ...your params... };
$.each(params, function (k, v) {
    form.append($('<input>', {'type': 'hidden', 'name': k, 'value': v}));
});

//Make it part of the document and submit
$('body').append(form);
form.submit();

//Clean up
form.remove();

请注意,我大量使用JQuery,但你可以使用原生JS。

答案 11 :(得分:2)

正如其他人所说,您可以通过POST请求创建并提交表单以进行下载。但是,您不必手动执行此操作。

正是这样做的一个非常简单的库是jquery.redirect。它提供了与标准jQuery.post方法类似的API:

$.redirect(url, [values, [method, [target]]])

答案 12 :(得分:1)

见:http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/ 它会返回一个blob作为响应,然后可以将其放入filesaver

答案 13 :(得分:1)

以下是我的解决方案,用于根据包含某些ID的某些列表下载多个文件,并在数据库中查找文件,这些文件将被确定并可以下载-如果存在的话。 我正在使用Ajax为每个文件调用C#MVC操作。

是的,就像其他人所说的,可以在jQuery Ajax中做到这一点。 我做到了Ajax的成功,而且我总是发送回复200。

所以,这是关键:

  success: function (data, textStatus, xhr) {

这是我的代码:

var i = 0;
var max = 0;
function DownloadMultipleFiles() {
            if ($(".dataTables_scrollBody>tr.selected").length > 0) {
                var list = [];
                showPreloader();
                $(".dataTables_scrollBody>tr.selected").each(function (e) {
                    var element = $(this);
                    var orderid = element.data("orderid");
                    var iscustom = element.data("iscustom");
                    var orderlineid = element.data("orderlineid");
                    var folderPath = "";
                    var fileName = "";

                    list.push({ orderId: orderid, isCustomOrderLine: iscustom, orderLineId: orderlineid, folderPath: folderPath, fileName: fileName });
                });
                i = 0;
                max = list.length;
                DownloadFile(list);
            }
        }

然后致电:

function DownloadFile(list) {
        $.ajax({
            url: '@Url.Action("OpenFile","OrderLines")',
            type: "post",
            data: list[i],
            xhrFields: {
                responseType: 'blob'
            },
            beforeSend: function (xhr) {
                xhr.setRequestHeader("RequestVerificationToken",
                    $('input:hidden[name="__RequestVerificationToken"]').val());

            },
            success: function (data, textStatus, 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 a = document.createElement('a');
                    var url = window.URL.createObjectURL(data);
                    a.href = url;
                    a.download = filename;
                    document.body.append(a);
                    a.click();
                    a.remove();
                    window.URL.revokeObjectURL(url);
                }
                else {
                    getErrorToastMessage("Production file for order line " + list[i].orderLineId + " does not exist");
                }
                i = i + 1;
                if (i < max) {
                    DownloadFile(list);
                }
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {

            },
            complete: function () {
                if(i===max)
                hidePreloader();
            }
        });
    }

C#MVC:

 [HttpPost]
 [ValidateAntiForgeryToken]
public IActionResult OpenFile(OrderLineSimpleModel model)
        {
            byte[] file = null;

            try
            {
                if (model != null)
                {
                    //code for getting file from api - part is missing here as not important for this example
                    file = apiHandler.Get<byte[]>(downloadApiUrl, token);

                    var contentDispositionHeader = new System.Net.Mime.ContentDisposition
                    {
                        Inline = true,
                        FileName = fileName
                    };
                    //    Response.Headers.Add("Content-Disposition", contentDispositionHeader.ToString() + "; attachment");
                    Response.Headers.Add("Content-Type", "application/pdf");
                    Response.Headers.Add("Content-Disposition", "attachment; filename=" + fileName);
                    Response.Headers.Add("Content-Transfer-Encoding", "binary");
                    Response.Headers.Add("Content-Length", file.Length.ToString());

                }
            }
            catch (Exception ex)
            {
                this.logger.LogError(ex, "Error getting pdf", null);
                return Ok();
            }

            return File(file, System.Net.Mime.MediaTypeNames.Application.Pdf);
        }

只要返回响应200,Ajax中的成功就可以使用它,您可以检查文件是否实际存在,因为在这种情况下,以下行将为false,您可以通知用户:

 if (disposition && disposition.indexOf('attachment') !== -1) {

答案 14 :(得分:1)

要让Jonathan Amends answer在Edge中工作,我做了以下更改:

var blob = typeof File === 'function'
    ? new File([this.response], filename, { type: type })
    : new Blob([this.response], { type: type });

到这个

var f = typeof File+"";
var blob = f === 'function' && Modernizr.fileapi
    ? new File([this.response], filename, { type: type })
    : new Blob([this.response], { type: type });

我宁愿将此作为评论发布,但我没有足够的声誉

答案 15 :(得分:1)

我使用了这个FileSaver.js。在我使用csv文件的情况下,我做了这个(在coffescript中):

  $.ajax
    url: "url-to-server"
    data: "data-to-send"
    success: (csvData)->
      blob = new Blob([csvData], { type: 'text/csv' })
      saveAs(blob, "filename.csv")

我认为对于最复杂的情​​况,必须正确处理数据。在引擎盖下FileSaver.js实现Jonathan Amend答案的相同方法。

答案 16 :(得分:0)

这是我的解决方案,来自不同的来源: 服务器端实现:

    String contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
    // Set headers
    response.setHeader("content-disposition", "attachment; filename =" + fileName);
    response.setContentType(contentType);
    // Copy file to output stream
    ServletOutputStream servletOutputStream = response.getOutputStream();
    try (InputStream inputStream = new FileInputStream(file)) {
        IOUtils.copy(inputStream, servletOutputStream);
    } finally {
        servletOutputStream.flush();
        Utils.closeQuitely(servletOutputStream);
        fileToDownload = null;
    }

客户端实现(使用jquery):

$.ajax({
type: 'POST',
contentType: 'application/json',
    url: <download file url>,
    data: JSON.stringify(postObject),
    error: function(XMLHttpRequest, textStatus, errorThrown) {
        alert(errorThrown);
    },
    success: function(message, textStatus, response) {
       var header = response.getResponseHeader('Content-Disposition');
       var fileName = header.split("=")[1];
       var blob = new Blob([message]);
       var link = document.createElement('a');
       link.href = window.URL.createObjectURL(blob);
       link.download = fileName;
       link.click();
    }
});   

答案 17 :(得分:0)

还有另一种解决方案,可以用ajax下载网页。但是我指的是必须先处理然后下载的页面。

首先,您需要将页面处理与结果下载分开。

1)在ajax调用中仅进行页面计算。

$.post("CalculusPage.php", { calculusFunction: true, ID: 29, data1: "a", data2: "b" },

       function(data, status) 
       {
            if (status == "success") 
            {
                /* 2) In the answer the page that uses the previous calculations is downloaded. For example, this can be a page that prints the results of a table calculated in the ajax call. */
                window.location.href = DownloadPage.php+"?ID="+29;
            }               
       }
);

// For example: in the CalculusPage.php

    if ( !empty($_POST["calculusFunction"]) ) 
    {
        $ID = $_POST["ID"];

        $query = "INSERT INTO ExamplePage (data1, data2) VALUES ('".$_POST["data1"]."', '".$_POST["data2"]."') WHERE id = ".$ID;
        ...
    }

// For example: in the DownloadPage.php

    $ID = $_GET["ID"];

    $sede = "SELECT * FROM ExamplePage WHERE id = ".$ID;
    ...

    $filename="Export_Data.xls";
    header("Content-Type: application/vnd.ms-excel");
    header("Content-Disposition: inline; filename=$filename");

    ...

我希望这种解决方案对我来说对许​​多人都有用。

答案 18 :(得分:0)

如果响应是 Array Buffer ,请在Ajax中的onsuccess事件下尝试以下操作:

 if (event.data instanceof ArrayBuffer) {
          var binary = '';
          var bytes = new Uint8Array(event.data);
          for (var i = 0; i < bytes.byteLength; i++) {
              binary += String.fromCharCode(bytes[i])
          }
          $("#some_id").append("<li><img src=\"data:image/png;base64," + window.btoa(binary) + "\"/></span></li>");
          return;
      }
  • 其中event.data是xhr事件的成功函数中收到的响应。

答案 19 :(得分:0)

我需要与@ alain-cruz相似的解决方案,但在nuxt / vue中需要多次下载。我知道浏览器会阻止多个文件下载,我也有API,该API返回一组csv格式的数据。起初我打算使用JSZip,但是我需要IE支持,所以这是我的解决方案。如果有人可以帮助我改善这一点,那将是不错的选择,但到目前为止,它对我来说一直有效。

API返回:

data : {
  body: {
    fileOne: ""col1", "col2", "datarow1.1", "datarow1.2"...so on",
    fileTwo: ""col1", "col2"..."
  }
}

page.vue:

<template>
  <b-link @click.prevent="handleFileExport">Export<b-link>
</template>

export default = {
   data() {
     return {
       fileNames: ['fileOne', 'fileTwo'],
     }
   },
  computed: {
    ...mapState({
       fileOne: (state) => state.exportFile.fileOne,
       fileTwo: (state) => state.exportFile.fileTwo,
    }),
  },
  method: {
    handleExport() {
      //exportFileAction in store/exportFile needs to return promise
      this.$store.dispatch('exportFile/exportFileAction', paramsToSend)
        .then(async (response) => {
           const downloadPrep = this.fileNames.map(async (fileName) => {
           // using lodash to get computed data by the file name
           const currentData = await _.get(this, `${fileName}`);
           const currentFileName = fileName;
           return { currentData, currentFileName };
         });
         const response = await Promise.all(downloadPrep);
         return response;
       })
       .then(async (data) => {
         data.forEach(({ currentData, currentFileName }) => {
           this.forceFileDownload(currentData, currentFileName);
         });
       })
       .catch(console.error);
    },
    forceFileDownload(data, fileName) {
     const url = window.URL
         .createObjectURL(new Blob([data], { type: 'text/csv;charset=utf-8;' }));
     const link = document.createElement('a');
     link.href = url;
     link.setAttribute('download', `${fileName}.csv`);
     document.body.appendChild(link);
     link.click();
   },
}
相关问题