通过AJAX调用提示用户保存文件

7
我正在将我的DHTMLX网格导出为csv,并成功创建了.CSV文件。我遇到的问题是它没有提示用户保存/打开文件。我使用JavaScript中的$.post调用将CSV字符串发送到PHP,然后将该字符串写入csv。由于某种原因,它没有为用户创建提示,但它成功地编写了文件并保存在服务器上。以下是相关代码:
JS:
myGrid.csvParser = myGrid.csvExtParser;
myGrid.setCSVDelimiter('|');
myGrid.csv.row = "endOfRow";           
var gridCsvData = myGrid.serializeToCSV();

    $.post(
        "data/export.php", 
        { 
           csvdata: gridCsvData
        }
    );

PHP(export.php):

$csvData = $_REQUEST['csvdata'];

$csv = explode('endOfRow',$csvData);

$myfile = "grid.csv";

$fh = fopen($myfile, 'w') or die("can't open file");

foreach($csv as $line) {
    fputcsv($fh, explode('|',$line),',','"');
}

fclose($fh);

//Redirect output to a client's web browser (csv)
header("Content-type: application/csv");
header("Content-Disposition: attachment; filename=grid.csv");
header("Pragma: no-cache");
header("Expires: 0");

这段代码可以完美地将Grid导出为我想要的格式并保存到'grid.csv'文件中。问题在于它没有提示用户保存文件。这是我的PHP头部有问题还是我需要在$.post中加入某些内容来提示成功?感谢任何帮助!

2个回答

14

您无法通过 AJAX 调用提示用户下载文件。您可以创建一个 iFrame,并在其中放置一个表单,然后进行 POST 请求。这样,它看起来像是一个 AJAX 调用,但用户将被提示下载该文件。

// Create iFrame
var iframe = document.createElement('iframe');
iframe.style.display = "none";
document.body.appendChild(iframe);

// Get the iframe's document
var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

// Make a form
var form = document.createElement('form');
form.action = 'data/export.php'; // Your URL
form.method = 'POST';

// Add form element, to post your value
var input = document.createElement('input');
input.type = 'hidden';
input.name = 'csvdata';
input.value = gridCsvData;  // Your POST data

// Add input to form
form.appendChild(input);

// Add form to iFrame
// IE doesn't have the "body" property
(iframeDoc.body || iframeDoc).appendChild(form);

// Post the form :-)
form.submit();

附注:你的PHP代码并没有在屏幕上输出CSV,而是将其保存到了文件中。

在调用header函数后,请确保添加以下代码:

readfile($myfile);

看起来很有前途。目前正在处理错误:“body”为空或不是对象,位于“iframeDoc.body.appendChild(form);”行上。有什么想法吗?谢谢! - ad2387
@adaher23:我更新了答案,请试一下。IE不支持.body属性。如果你可以使用jQuery,我建议使用它。它可以解决这些愚蠢的跨浏览器问题。 - gen_Eric
2
您也可以在当前文档中添加一个表单元素,而不是使用 iframe,效果相同。 - Heretic Monkey
@MikeMcCaughan:嗯,我没有想到那个。由于文件下载不算页面加载,所以那也可以。我只是更喜欢使用iframe,以防万一。 - gen_Eric
哇,太感谢了。非常好用,如果我能接受两次的话,我一定会的。 - ad2387
显示剩余2条评论

2
在HTML5中正确的方法是使用File API。有关详细信息,请参见此处:http://hackworthy.blogspot.com/2012/05/savedownload-data-generated-in.html
如果无法使用HTML5,则可以采用以下方法。
在进行POST后,使用以下代码生成文件的GET请求:
document.location = "file.csv";

根据浏览器的不同,文件要么会被保存(Chrome),要么会提示用户选择一个文件名进行保存。当然,POST处理程序必须在某个地方保存文件。

$.ajax({
    type: "POST",
    url: "post.php",
    success: function() {
        console.log("Worked!");
        document.location = "test.csv";
    },
    error: function() {
        console.log("Failed!");
    }
});

关于 document.location 的部分无法正常工作。 - arxpoetica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接