使用ajax请求下载文件

时间:2013-12-29 21:35:10

标签: javascript php ajax file download

我想点击按钮时发送“ajax下载请求”,所以我试着这样:

的javascript:

var xhr = new XMLHttpRequest();
xhr.open("GET", "download.php");
xhr.send();

的download.php:

<?
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename= file.txt");
header("Content-Transfer-Encoding: binary");    
readfile("file.txt");
?>

但是没有按预期工作,我该怎么办?提前谢谢

13 个答案:

答案 0 :(得分:89)

2015年4月27日更新

来到HTML5场景的是download attribute。在Firefox和Chrome中它是supported,很快就会进入IE11。根据您的需要,您可以使用它而不是AJAX请求(或使用window.location),只要您要下载的文件与您的网站位于同一来源。

您可以使用some JavaScript来测试是否支持window.location,如果不支持,则可以使AJAX请求/ download成为后备,将其切换为window.location。< / p>

原始回答

您不能让AJAX请求打开下载提示,因为您必须导航到该文件以提示下载。相反,您可以使用成功函数导航到download.php。这将打开下载提示,但不会更改当前页面。

$.ajax({
    url: 'download.php',
    type: 'POST',
    success: function() {
        window.location = 'download.php';
    }
});

即使这回答了问题,最好只使用window.location并完全避免AJAX请求。

答案 1 :(得分:38)

你实际上根本不需要ajax。如果您只是将“download.php”设置为按钮上的href,或者,如果它不是链接,则使用:

window.location = 'download.php';

浏览器应识别二进制下载而不加载实际页面,只是将文件作为下载文件提供。

答案 2 :(得分:29)

要让浏览器下载文件,您需要发出以下命令:

 function downloadFile(urlToSend) {
     var req = new XMLHttpRequest();
     req.open("GET", urlToSend, true);
     req.responseType = "blob";
     req.onload = function (event) {
         var blob = req.response;
         var fileName = req.getResponseHeader("fileName") //if you have the fileName header available
         var link=document.createElement('a');
         link.href=window.URL.createObjectURL(blob);
         link.download=fileName;
         link.click();
     };

     req.send();
 }

答案 3 :(得分:13)

有可能。您可以从ajax函数内部开始下载,例如,在创建.csv文件之后。

我有一个ajax函数,可以将联系人数据库导出到.csv文件,在完成后,它会自动启动.csv文件下载。所以,在我得到responseText并且一切正常之后,我会像这样重定向浏览器:

window.location="download.php?filename=export.csv";

我的 download.php 文件如下所示:

<?php

    $file = $_GET['filename'];

    header("Cache-Control: public");
    header("Content-Description: File Transfer");
    header("Content-Disposition: attachment; filename=".$file."");
    header("Content-Transfer-Encoding: binary");
    header("Content-Type: binary/octet-stream");
    readfile($file);

?>

没有任何页面刷新,文件会自动开始下载。

注意 - 在以下浏览器中进行了测试:

Chrome v37.0.2062.120 
Firefox v32.0.1
Opera v12.17
Internet Explorer v11

答案 4 :(得分:12)

跨浏览器解决方案,在Chrome,Firefox,Edge,IE11上测试。

在DOM中,添加隐藏的链接标记:

<a id="target" style="display: none"></a>

然后:

var req = new XMLHttpRequest();
req.open("GET", downloadUrl, true);
req.responseType = "blob";

req.onload = function (event) {
  var blob = req.response;
  var fileName = null;
  var contentType = req.getResponseHeader("content-type");

  // IE/EDGE seems not returning some response header
  if (req.getResponseHeader("content-disposition")) {
    var contentDisposition = req.getResponseHeader("content-disposition");
    fileName = contentDisposition.substring(contentDisposition.indexOf("=")+1);
  } else {
    fileName = "unnamed." + contentType.substring(contentType.indexOf("/")+1);
  }

  if (window.navigator.msSaveOrOpenBlob) {
    // Internet Explorer
    window.navigator.msSaveOrOpenBlob(new Blob([blob], {type: contentType}), fileName);
  } else {
    var el = document.getElementById("target");
    el.href = window.URL.createObjectURL(blob);
    el.download = fileName;
    el.click();
  }
};
req.send();

答案 5 :(得分:3)

我更喜欢location.assign(url);

完整的语法示例:

document.location.assign('https://www.urltodocument.com/document.pdf');

developer.mozilla.org/en-US/docs/Web/API/Location.assign

答案 6 :(得分:0)

从标题中解码文件名有点复杂......

    var filename = "default.pdf";
    var disposition = req.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, '');
    }

答案 7 :(得分:0)

此解决方案与上面的解决方案并没有太大不同,但是对我来说,它的效果很好,而且我认为它很干净。

我建议对文件服务器端进行base64编码(如果使用的是PHP,则为base64_encode()),然后将base64编码的数据发送给客户端

在客户端上,您可以这样做:

 let blob = this.dataURItoBlob(THE_MIME_TYPE + "," + response.file);
 let uri = URL.createObjectURL(blob);
 let link = document.createElement("a");
 link.download = THE_FILE_NAME,
 link.href = uri;
 document.body.appendChild(link);
 link.click();
 document.body.removeChild(link);

此代码将编码后的数据放在链接中,并模拟对链接的点击,然后将其删除。

答案 8 :(得分:0)

您的需求得到满足  window.location('download.php');
但是我认为您需要传递要下载的文件,而不总是下载相同的文件,因此这就是您使用请求的原因,一种选择是创建一个像showfile.php一样简单的php文件,并执行类似< / p>

var myfile = filetodownload.txt
var url = "shofile.php?file=" + myfile ;
ajaxRequest.open("GET", url, true);

showfile.php

<?php
$file = $_GET["file"] 
echo $file;

其中file是在请求中通过Get或Post传递的文件名,然后仅在函数中捕获响应

if(ajaxRequest.readyState == 4){
                        var file = ajaxRequest.responseText;
                        window.location = 'downfile.php?file=' + file;  
                    }
                }

答案 9 :(得分: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");

    ...

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

答案 10 :(得分:0)

对于那些寻求更现代方法的人,可以使用crossprod(newx, newy) / (sqrt(sum(newx^2)) * sqrt(sum(newy^2))) [,1] [1,] 0.5991713 。以下示例显示了如何下载电子表格文件。使用以下代码即可轻松完成。

fetch API

我认为,这种方法比其他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方法类似,而无需添加任何其他库。

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

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

答案 11 :(得分:0)

@Joao Marcos解决方案对我有用,但我必须修改代码以使其在IE上工作,如果代码看起来像这样,则在下面

       downloadFile(url,filename) {
        var that = this;
        const extension =  url.split('/').pop().split('?')[0].split('.').pop();

        var req = new XMLHttpRequest();
        req.open("GET", url, true);
        req.responseType = "blob";
        req.onload = function (event) {
            const fileName = `${filename}.${extension}`;
            const blob = req.response;

            if (window.navigator.msSaveBlob) { // IE
                window.navigator.msSaveOrOpenBlob(blob, fileName);
            } 
            const link = document.createElement('a');
            link.href = window.URL.createObjectURL(blob);                
            link.download = fileName;
            link.click();
            URL.revokeObjectURL(link.href);

        };

        req.send();
    },

答案 12 :(得分:0)

这对我有用

var dataObj = {
somekey:"someValue"
}
     $.ajax({
        method: "POST",
        url: "/someController/someMethod",
        data: dataObj,
        success: function (response) {
            const blob = new Blob([response], { type: 'text/csv' });
            const downloadUrl = URL.createObjectURL(blob);
            const a = document.createElement("a");
            a.href = downloadUrl;
            a.download = "file.csv";
            document.body.appendChild(a);
            a.click();
        }
    });