【问题标题】:Download CSV file using "AJAX"使用“AJAX”下载 CSV 文件
【发布时间】:2010-07-27 17:11:09
【问题描述】:

我正在尝试为我的网站完成一项相当简单的任务,但我不确定该怎么做。我希望用户查看表格,然后单击按钮,此时用户可以将该表的内容保存为 csv 文件。此请求有时可能非常复杂,因此我会生成一个进度页面来提醒用户。

除了实际生成 csv 文件之外,我已经弄清楚了大多数事情。 (我使用 jQuery 和 PHP)

点击时运行的 jQuery 代码:

hmis_query_csv_export: function(query_name) {
    $.uiLock('<p>Query Loading.</p><img src="/images/loading.gif" />')
    $.get({
        url: '/php_scripts/utils/csv_export.php',
        data: {query_name: query_name},
        success: function(data) {
            $.uiUnlock();
        }
    });}

相关的PHP:

header("Content-type: text/x-csv");
header("Content-Disposition: attachment; filename=search_results.csv");
//
//Generate csv
//
echo $csvOutput
exit();

它的作用是将文本作为 PHP 文件发送,但不会生成下载。我做错了什么?

【问题讨论】:

    标签: php ajax csv


    【解决方案1】:

    如果您要强制下载,您可以将当前页面重定向到下载链接。由于该链接将生成一个下载对话框,因此当前页面(及其状态)将保持不变。

    基本方法:

    $('a#query_name').click(function(){
        $('#wait-animation').show();
        document.location.href = '/php_scripts/utils/csv_export.php?query_name='+query_name;
        $('#wait-animation').hide();
    });
    

    更复杂:

    $('a#query_name').click(function(){
        MyTimestamp = new Date().getTime(); // Meant to be global var
        $('#wait-animation').show();
        $.get('/php_scripts/utils/csv_export.php','timestamp='+MyTimestamp+'&query_name='query_name,function(){
            document.location.href = '/php_scripts/utils/csv_export.php?timestamp='+MyTimestamp+'&query_name='+query_name;
            $('#wait-animation').hide();
        });
    });
    

    在 PHP 脚本中:

    @header("Last-Modified: " . @gmdate("D, d M Y H:i:s",$_GET['timestamp']) . " GMT");
    @header("Content-type: text/x-csv");
    // If the file is NOT requested via AJAX, force-download
    if(!isset($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest') {
        header("Content-Disposition: attachment; filename=search_results.csv");
    }
    //
    //Generate csv
    //
    echo $csvOutput
    exit();
    

    两个请求的 URL 必须相同,以欺骗浏览器不在document.location.href 开始新的下载,而是将副本保存在缓存中。我不完全确定,但看起来很有希望。

    【讨论】:

    • 非常感谢您的提示。我可以很容易地让它工作,但我想知道如何在实现屏幕锁定和进度动画的同时使用它。我只是担心用户可能会感到困惑,因为根据查询的不同,此过程可能需要 3 或 4 分钟。
    • 如果创建 CSV 文件需要很长时间,您可能需要稍微改变方向,改为使用 AJAX 启动 PHP 脚本来创建临时磁盘文件;一旦 PHP 脚本返回(带有文件名),AJAX 回调函数就可以进行重定向,如 Ast Derek 所示。
    • 所以您的编辑看起来应该可以工作,但似乎语句正在异步运行。第三条语句不等待下载完成,所以等待屏幕出现然后立即消失。有没有办法强制它同步运行?
    • @godheadatomic 我对此有人为的限制。我转发的信息是机密的,我不允许将其保存在网络服务器(与数据库分开)上,即使是暂时的。到目前为止,这种限制给我带来了很多问题..
    • 进度对话框很棘手。我在这里遇到了类似的问题:stackoverflow.com/questions/1106377/… 但从未真正解决过。
    【解决方案2】:

    编辑 我刚刚用一个 10MB 的文件尝试了这个,看来 val() 插入数据太慢了。哼哼。


    好的,所以我再试一次。这可能是也可能不是完全疯狂!这个想法是发出一个AJAX请求来创建数据,然后使用回调将数据插入到当前页面上的隐藏表单中,该表单具有第三个“下载”页面的动作;插入后,表单自动提交,下载页面发送标题并回显POST,然后瞧,下载。

    一直以来,在原始页面上,您都会看到文件正在准备中的指示,并且当它完成时,指示符会更新。

    注意:此测试代码没有经过广泛测试,也没有真正的安全检查(或任何安全检查)。我用我放置的 1.5MB CSV 文件对其进行了测试,它相当活泼。

    Index.html

    <a id="downloadlink" href="#">Click Me</a>
    <div id="wait"></div>
    <form id="hiddenform" method="POST" action="download.php">
        <input type="hidden" id="filedata" name="data" value="">
    </form>
    

    test.js

    $(document).ready(function(){
      $("#downloadlink").click(function(){       // click the link to download
          lock();                                // start indicator
          $.get("create.php",function(filedata){ // AJAX call returns with CSV file data
              $("#filedata").val(filedata);      // insert into the hidden form
              unlock();                          // update indicator
              $("#hiddenform").submit();         // submit the form data to the download page
          });
      });
    
      function lock(){
          $("#wait").text("Creating File...");
      }
    
      function unlock(){
          $("#wait").text("Done");
      }
    });
    

    create.php

    <?php
    //create $data
    print $data;
    ?>
    

    download.php

    <?php
    header("Pragma: public");
    header("Expires: 0"); 
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    header("Content-Type: text/x-csv");
    header("Content-Disposition: attachment;filename=\"search_results.csv\""); 
    
    if($_POST['data']){
        print $_POST['data'];
    }
    ?>
    

    【讨论】:

      【解决方案3】:

      完成此操作的最佳方法是使用如下数据 URI:

      1. 像往常一样对服务器进行 AJAX 调用
      2. 在服务器端生成 CSV
      3. 返回数据(裸数据或 JSON 结构内)
      4. 使用返回的数据在 Javascript 中创建数据 URI
      5. 将 window.location.href 设置为数据 URI

      有关说明,请参阅此链接(特别是第 3 段):http://en.wikipedia.org/wiki/Data_URI_scheme

      这样,您无需在服务器上保存任何文件,也无需使用 iframe 或隐藏的表单元素或任何此类技巧。

      【讨论】:

        【解决方案4】:

        我认为您不能使用 AJAX/JS 请求进行浏览器下载。尝试使用隐藏的 iframe 导航到生成 CSV 的页面

        【讨论】:

          【解决方案5】:

          使用 AJAX 的目的是避免页面的可见重新加载。如果你想要下载,你想要相反的——来自浏览器的全新请求。我想说,只需创建一个指向您的 php 页面的简单按钮。

          【讨论】:

          • 好的,如果我这样做,我将如何将加载动画和 UI 锁定集成到其中?这难道不是使用 AJAX 的理由吗?另外,我对此很陌生,我不确定将 GET 参数集成到页面请求中时的最佳方法。
          • @The_Denominator 使用 iframe
          【解决方案6】:

          要回应和扩展其他人所说的内容,您不能真正使用 AJAX 发送文件。造成这种情况的原因之一是(如果我在这方面错了,请有人纠正我)您当前所在的页面已经发送了它的内容标题;即使使用 AJAX 请求(这是您的 PHP 文件正在尝试执行的操作),您也无法将它们再次发送到同一个窗口。

          我之前在项目中所做的只是提供一个链接(带有 target="_blank" 或 javascript 重定向)到单独的下载 PHP 页面。如果您使用的是 Apache,请同时查看 mod_xsendfile。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-05-27
            • 1970-01-01
            • 1970-01-01
            • 2023-03-16
            • 2015-06-01
            • 2020-10-28
            • 2021-09-09
            • 1970-01-01
            相关资源
            最近更新 更多