下载 csv 文件作为对 AJAX 请求的响应

Posted

技术标签:

【中文标题】下载 csv 文件作为对 AJAX 请求的响应【英文标题】:Download csv file as response on AJAX request 【发布时间】:2018-03-20 04:25:57 【问题描述】:

我有一个名为“/downloadUserAction”的端点,它收集数据并下载 csv 文件。我面临的挑战是,使用单击功能上的按钮调用端点时不会下载文件,但是只有当我直接在浏览器中访问端点时才会下载。

经过研究,我发现了一些结论,即您不能使用 AJAX 下载文件。这是有道理的,因为当我单击我的按钮时,我看到端点被击中并且文件内容正在网络选项卡中传递,但是没有文件被下载到客户端上。

这就是我在 javascript 端使用我页面上的数据表按钮插件功能调用我的端点所做的所有事情。

$(document).ready(function () 
    var table = $("#userActivity").on('init.dt', function() 
            ).DataTable(
                dom: 'Blfrtip',
                buttons: [
                          
                            extend: 'csvhtml5',
                            text: 'NLP Search Download',
                            action: function ( e, dt, node, config ) 
                                $.ajax(
                                    url : window.location + "/downloadUserAction?draw=3&search%5Bvalue%5D=NLP_SEARCH&order%5B0%5D%5Bcolumn%5D=6&order%5B0%5D%5Bdir%5D=desc"                        
                                );
                            
                          
                      ],

是否有另一种调用我的端点的方法会强制在客户端页面上下载?

旁注:我的数据表正在使用服务器端处理,否则我只会使用数据表 csv 导出按钮。

【问题讨论】:

【参考方案1】:

在现代浏览器中,您可以通过使用文件内容(在您的情况下由 Ajax 接收)创建 Blob、为其创建 URL 并使用 download 属性来提示下载:

const saveData = (function () 
    const a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
    return function (data, fileName) 
        const blob = new Blob([data], type: "octet/stream"),
            url = window.URL.createObjectURL(blob);
        a.href = url;
        a.download = fileName;
        a.click();
        window.URL.revokeObjectURL(url);
    ;
());

const data = 'a,b,c\n5,6,7',
    fileName = "my-csv.csv";

saveData(data, fileName);

JSFiddle

如果您的 Ajax 端点 URL 具有正确的标头(或者即使它没有,只要您使用 download 属性),您可以放弃 Blob 和 Ajax,只需将 URL 添加到带有下载属性。改编@pritesh的代码,

const saveData = (function () 
    const a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
    return function (url, fileName) 
        a.href = url;
        a.download = fileName;
        a.click();
    ;
());

const url = 'http://www.sample-videos.com/csv/Sample-Spreadsheet-10-rows.csv', // Replace with your own URL: window.location + "/downloadUserAction?draw=3&search%5Bvalue%5D=NLP_SEARCH&order%5B0%5D%5Bcolumn%5D=6&order%5B0%5D%5Bdir%5D=desc"
    fileName = "my-csv.csv";

saveData(url, fileName);

JSFiddle

【讨论】:

应该在用a.remove()点击锚点后移除锚点。 我建立了闭包,因为我认为在内存中拥有一个链接比每次都创建和销毁一个链接要好。【参考方案2】:

即使这是一个老问题,我也想发布我想出的答案,因为我遇到了同样的问题。

还有一种替代方法可以在客户端直接使用FileSaver.js 库保存blob,而不是创建链接并调用click 方法。

添加FileSaver.js后,您可以简单地使用saveAS(blob, filename)启动下载。

以下示例用于处理 Flask 服务器 send_file(file, as_attachment=True, attachment_filename='export.csv', mimetype='text/csv') 响应。

function downloadCsv() 
  jQuery.ajax(
    async: true,
    url: URL,
    timeout: 5000,
    type: "post",
    xhrFields: 
      responseType: "blob", // to avoid binary data being mangled on charset conversion
    ,
    data: postRequestdata,
    error: function (e) 
      console.error(e);
    ,
    // in jQuery 1.4+ when the success callback its executed three arguments are passed (success(data, textStatus, XMLHttpRequest))
    success: function (blob, status, xhr) 
      // check for a filename
      var filename = "";
      var disposition = xhr.getResponseHeader("Content-Disposition");
      if(disposition && disposition.indexOf("filename") !== -1)
        splitted = disposition.split("filename=");
        filename = splitted[splitted.length-1];
        saveAs(blob, filename);
      
    ,
  );

【讨论】:

【参考方案3】:

由于它是在您直接从浏览器访问端点时下载的,所以您可以在按钮内设置一个锚标记,并将锚标记的 href 属性设置为指向 csv 文件的 url。我已经创建这里有一个示例:

<!DOCTYPE html>
<html>
<head>
    <title>Test</title>
</head>
<body>
    <button>
        <a href="http://www.sample-videos.com/csv/Sample-Spreadsheet-10-rows.csv">Click me</a>
    </button>
</body>
</html>

如果您在浏览器中试用此代码,则单击时会出现一个对话框用于保存文件。

在您的情况下,您需要将示例视频网址替换为您自己的。

window.location + "/downloadUserAction?draw=3&search%5Bvalue%5D=NLP​​_SEARCH&order%5B0%5D%5Bcolumn%5D=6&order%5B0%5D%5Bdir%5D=desc"

【讨论】:

以上是关于下载 csv 文件作为对 AJAX 请求的响应的主要内容,如果未能解决你的问题,请参考以下文章

下载 excel 文件的 ajax 请求显示我被截断的响应

下载 excel 文件的 ajax 请求显示我被截断的响应

如何对从 AJAX 请求中获取的响应进行排序并将它们作为 <option> 映射到 <select> 标记?

通过发送ajax请求下载Excel文件

在 ajax 请求中获取不正确的 json 响应

ajax响应时长怎样设置?