简体   繁体   English

使用“AJAX”下载CSV文件

[英]Download CSV file using “AJAX”

I'm trying to accomplish a fairly simple task for my website, but I"m not sure exactly how to go about it. I want the user to be viewing a table, then click a button, at which point the user can save the contents of that table as a csv file. This request can sometimes be quite complicated so I generate a progress page to alert the user. 我正在尝试为我的网站完成一个相当简单的任务,但我不确定如何去做。我希望用户查看一个表,然后单击一个按钮,此时用户可以保存该表的内容为csv文件。此请求有时可能非常复杂,因此我生成一个进度页面以提醒用户。

I have most things figured out except actually generating the csv file. 除了实际生成csv文件之外,我发现了大多数事情。 (I use jQuery and PHP) (我使用jQuery和PHP)

the jQuery code run on click: 点击运行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();
        }
    });}

the relevant PHP: 相关的PHP:

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

What this does is sends the text as the PHP file, but it's doesn't generate a download. 这样做是将文本作为PHP文件发送,但它不会生成下载。 What am I doing wrong? 我究竟做错了什么?

If you are forcing a download, you can redirect the current page to the download link. 如果要强制下载,可以将当前页面重定向到下载链接。 Since the link will generate a download dialog, the current page (and its state) will be kept in place. 由于链接将生成下载对话框,因此当前页面(及其状态)将保留在原位。

Basic approach: 基本方法:

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

More complicated: 更复杂:

$('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();
    });
});

At PHP script: 在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();

The URL for both requests must be the same to trick the browser not to start a new download at document.location.href , but to save the copy at the cache. 两个请求的URL必须相同才能欺骗浏览器不要在document.location.href开始新的下载,而是将副本保存在缓存中。 I'm not totally sure about it, but seems pretty promising. 我不是很确定,但看起来很有希望。

EDIT I just tried this with a 10MB file and it seems that val() is too slow to insert the data. 编辑我刚尝试使用10MB文件,似乎val()太慢,无法插入数据。 Hurrumph. Hurrumph。


Okay, so I gave this one another go. 好的,所以我给了另一个去。 This may or may not be completely insane! 这可能是也可能不是完全疯了! The idea is to make an AJAX request to create the data, then use the callback to insert the data into a hidden form on the current page which has an action of a third "download" page; 我们的想法是创建一个AJAX请求来创建数据,然后使用回调将数据插入到当前页面上的隐藏表单中,该页面具有第三个“下载”页面的操作; after the insertion, the form is automatically submitted, the download page sends headers and echoes the POST, and et voila, download. 插入后,表单自动提交,下载页面发送标题并回显POST,等等,下载。

All the while, on the original page you've got an indication that the file is being prepared, and when it finishes the indicator is updated. 一直以来,在原始页面上,您已经指示文件正在准备中,并且在完成时指示符已更新。

NOTE: this test code isn't tested extensively, and has no real security checks (or any at all) put in place. 注意:此测试代码未经过广泛测试,并且没有真正的安全检查(或根本没有)。 I tested it with a 1.5MB CSV file I had laying about and it was reasonably snappy. 我用1.5MB的CSV文件对它进行了测试,这个文件非常合理。

Index.html 的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 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 create.php

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

download.php 的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'];
}
?>

The best way to accomplish this is to use a Data URI as follows: 完成此任务的最佳方法是使用数据URI,如下所示:

  1. Make the AJAX call to the server as per normal 按正常方式对服务器进行AJAX调用
  2. Generate the CSV on the server-side 在服务器端生成CSV
  3. Return the data (either bare or inside a JSON structure) 返回数据(裸露或在JSON结构内)
  4. Create a Data URI in Javascript using the returned data 使用返回的数据在Javascript中创建数据URI
  5. Set window.location.href to the Data URI 将window.location.href设置为Data URI

See this link for instructions (paragraph #3, specifically): http://en.wikipedia.org/wiki/Data_URI_scheme 请参阅此链接以获取相关说明(特别是第3段): http//en.wikipedia.org/wiki/Data_URI_scheme

This way, you don't need to save any files on the server, and you also don't need to use iframes or hidden form elements or any such hacks. 这样,您不需要在服务器上保存任何文件,也不需要使用iframe或隐藏的表单元素或任何此类黑客。

I don't think you can make the browser download using a AJAX/JS request. 我认为您不能使用AJAX / JS请求进行浏览器下载。 Try using a hidden iframe that navigates to the page which generates the CSV 尝试使用导航到生成CSV的页面的隐藏iframe

Well the point of using AJAX is to avoid a visible reload of the page. 那么使用AJAX的目的是避免页面的可见重载。 If you want a download, you want the opposite,- a brand new request from the browser. 如果您想要下载,则需要相反的 - 来自浏览器的全新请求。 I'd say, just create a simple button pointing to your php page. 我会说,只需创建一个指向您的php页面的简单按钮。

To echo and expand on what others have said, you can't really send the file using AJAX. 为了回应和扩展其他人所说的内容,你无法使用AJAX真正发送文件。 One of the reasons for this is (and someone correct me if I'm wrong on this, please) that the page you're currently on already has sent its content headers; 造成这种情况的原因之一是(有人纠正我,如果我错了,请)您当前所在的页面已经发送了其内容标题; you can't send them again to the same window, even with an AJAX request (which is what your PHP file is attempting to do). 你不能再将它们发送到同一个窗口,即使有一个AJAX请求(这是你的PHP文件试图做的)。

What I've done before in projects is to simply provide a link (with target="_blank" or javascript redirect) to a separate download PHP page. 我之前在项目中所做的是简单地提供一个链接(带有target =“_ blank”或javascript重定向)到一个单独的下载PHP页面。 If you're using Apache, check out mod_xsendfile as well. 如果您正在使用Apache,请查看mod_xsendfile。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM